cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

module-sections.c (4570B)


      1/* SPDX-License-Identifier: GPL-2.0
      2 *
      3 * Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
      4 *
      5 * Copyright (C) 2018 Andes Technology Corporation <zong@andestech.com>
      6 */
      7
      8#include <linux/elf.h>
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/moduleloader.h>
     12
     13unsigned long module_emit_got_entry(struct module *mod, unsigned long val)
     14{
     15	struct mod_section *got_sec = &mod->arch.got;
     16	int i = got_sec->num_entries;
     17	struct got_entry *got = get_got_entry(val, got_sec);
     18
     19	if (got)
     20		return (unsigned long)got;
     21
     22	/* There is no duplicate entry, create a new one */
     23	got = (struct got_entry *)got_sec->shdr->sh_addr;
     24	got[i] = emit_got_entry(val);
     25
     26	got_sec->num_entries++;
     27	BUG_ON(got_sec->num_entries > got_sec->max_entries);
     28
     29	return (unsigned long)&got[i];
     30}
     31
     32unsigned long module_emit_plt_entry(struct module *mod, unsigned long val)
     33{
     34	struct mod_section *got_plt_sec = &mod->arch.got_plt;
     35	struct got_entry *got_plt;
     36	struct mod_section *plt_sec = &mod->arch.plt;
     37	struct plt_entry *plt = get_plt_entry(val, plt_sec, got_plt_sec);
     38	int i = plt_sec->num_entries;
     39
     40	if (plt)
     41		return (unsigned long)plt;
     42
     43	/* There is no duplicate entry, create a new one */
     44	got_plt = (struct got_entry *)got_plt_sec->shdr->sh_addr;
     45	got_plt[i] = emit_got_entry(val);
     46	plt = (struct plt_entry *)plt_sec->shdr->sh_addr;
     47	plt[i] = emit_plt_entry(val,
     48				(unsigned long)&plt[i],
     49				(unsigned long)&got_plt[i]);
     50
     51	plt_sec->num_entries++;
     52	got_plt_sec->num_entries++;
     53	BUG_ON(plt_sec->num_entries > plt_sec->max_entries);
     54
     55	return (unsigned long)&plt[i];
     56}
     57
     58static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y)
     59{
     60	return x->r_info == y->r_info && x->r_addend == y->r_addend;
     61}
     62
     63static bool duplicate_rela(const Elf_Rela *rela, int idx)
     64{
     65	int i;
     66	for (i = 0; i < idx; i++) {
     67		if (is_rela_equal(&rela[i], &rela[idx]))
     68			return true;
     69	}
     70	return false;
     71}
     72
     73static void count_max_entries(Elf_Rela *relas, int num,
     74			      unsigned int *plts, unsigned int *gots)
     75{
     76	unsigned int type, i;
     77
     78	for (i = 0; i < num; i++) {
     79		type = ELF_RISCV_R_TYPE(relas[i].r_info);
     80		if (type == R_RISCV_CALL_PLT) {
     81			if (!duplicate_rela(relas, i))
     82				(*plts)++;
     83		} else if (type == R_RISCV_GOT_HI20) {
     84			if (!duplicate_rela(relas, i))
     85				(*gots)++;
     86		}
     87	}
     88}
     89
     90int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
     91			      char *secstrings, struct module *mod)
     92{
     93	unsigned int num_plts = 0;
     94	unsigned int num_gots = 0;
     95	int i;
     96
     97	/*
     98	 * Find the empty .got and .plt sections.
     99	 */
    100	for (i = 0; i < ehdr->e_shnum; i++) {
    101		if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt"))
    102			mod->arch.plt.shdr = sechdrs + i;
    103		else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got"))
    104			mod->arch.got.shdr = sechdrs + i;
    105		else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got.plt"))
    106			mod->arch.got_plt.shdr = sechdrs + i;
    107	}
    108
    109	if (!mod->arch.plt.shdr) {
    110		pr_err("%s: module PLT section(s) missing\n", mod->name);
    111		return -ENOEXEC;
    112	}
    113	if (!mod->arch.got.shdr) {
    114		pr_err("%s: module GOT section(s) missing\n", mod->name);
    115		return -ENOEXEC;
    116	}
    117	if (!mod->arch.got_plt.shdr) {
    118		pr_err("%s: module GOT.PLT section(s) missing\n", mod->name);
    119		return -ENOEXEC;
    120	}
    121
    122	/* Calculate the maxinum number of entries */
    123	for (i = 0; i < ehdr->e_shnum; i++) {
    124		Elf_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset;
    125		int num_rela = sechdrs[i].sh_size / sizeof(Elf_Rela);
    126		Elf_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info;
    127
    128		if (sechdrs[i].sh_type != SHT_RELA)
    129			continue;
    130
    131		/* ignore relocations that operate on non-exec sections */
    132		if (!(dst_sec->sh_flags & SHF_EXECINSTR))
    133			continue;
    134
    135		count_max_entries(relas, num_rela, &num_plts, &num_gots);
    136	}
    137
    138	mod->arch.plt.shdr->sh_type = SHT_NOBITS;
    139	mod->arch.plt.shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
    140	mod->arch.plt.shdr->sh_addralign = L1_CACHE_BYTES;
    141	mod->arch.plt.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_entry);
    142	mod->arch.plt.num_entries = 0;
    143	mod->arch.plt.max_entries = num_plts;
    144
    145	mod->arch.got.shdr->sh_type = SHT_NOBITS;
    146	mod->arch.got.shdr->sh_flags = SHF_ALLOC;
    147	mod->arch.got.shdr->sh_addralign = L1_CACHE_BYTES;
    148	mod->arch.got.shdr->sh_size = (num_gots + 1) * sizeof(struct got_entry);
    149	mod->arch.got.num_entries = 0;
    150	mod->arch.got.max_entries = num_gots;
    151
    152	mod->arch.got_plt.shdr->sh_type = SHT_NOBITS;
    153	mod->arch.got_plt.shdr->sh_flags = SHF_ALLOC;
    154	mod->arch.got_plt.shdr->sh_addralign = L1_CACHE_BYTES;
    155	mod->arch.got_plt.shdr->sh_size = (num_plts + 1) * sizeof(struct got_entry);
    156	mod->arch.got_plt.num_entries = 0;
    157	mod->arch.got_plt.max_entries = num_plts;
    158	return 0;
    159}