Commit abb6e48f authored by Dong Kai's avatar Dong Kai Committed by Zheng Zengkai
Browse files

arm/module: Use plt section indices for relocations



hulk inclusion
category: feature
bugzilla: 51921
CVE: NA

---------------------------

We are planning to add livepatch without ftrace support for arm
in the next commit. However after commit 425595a7 ("livepatch:
reuse module loader code to write relocations") merged, the klp
relocations is done by apply_relocate function.

The mod->arch.{core,init}.plt pointers were problematic for livepatch
because they pointed within temporary section headers (provided by the
module loader via info->sechdrs) that would be freed after module load.

Here we take same modification based on commit c8ebf64e
("arm64/module: use plt section indices for relocations") to solve.

Signed-off-by: default avatarDong Kai <dongkai11@huawei.com>

Signed-off-by: default avatarYe Weihua <yeweihua4@huawei.com>
Reviewed-by: default avatarYang Jihong <yangjihong1@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 2b9ee60d
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ enum {
#endif

struct mod_plt_sec {
	struct elf32_shdr	*plt;
	int			plt_shndx;
	int			plt_count;
};

@@ -35,7 +35,8 @@ struct mod_arch_specific {
};

struct module;
u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val);
u32 get_module_plt(struct module *mod, Elf32_Shdr *sechdrs,
		   unsigned long loc, Elf32_Addr val);

#ifdef CONFIG_THUMB2_KERNEL
#define HAVE_ARCH_KALLSYMS_SYMBOL_VALUE
+25 −18
Original line number Diff line number Diff line
@@ -34,12 +34,14 @@ static bool in_init(const struct module *mod, unsigned long loc)
	return loc - (u32)mod->init_layout.base < mod->init_layout.size;
}

u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
u32 get_module_plt(struct module *mod, Elf32_Shdr *sechdrs,
		   unsigned long loc, Elf32_Addr val)
{
	struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core :
							  &mod->arch.init;

	struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr;
	struct plt_entries *plt =
		(struct plt_entries *)sechdrs[pltsec->plt_shndx].sh_addr;
	int idx = 0;

	/*
@@ -60,7 +62,8 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
	}

	pltsec->plt_count++;
	BUG_ON(pltsec->plt_count * PLT_ENT_SIZE > pltsec->plt->sh_size);
	BUG_ON(pltsec->plt_count * PLT_ENT_SIZE >
	       sechdrs[pltsec->plt_shndx].sh_size);

	if (!idx)
		/* Populate a new set of entries */
@@ -193,21 +196,23 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
	unsigned long init_plts = 0;
	Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
	Elf32_Sym *syms = NULL;
	Elf32_Shdr *core_pltsec, *init_pltsec;
	int i = 0;

	/*
	 * To store the PLTs, we expand the .text section for core module code
	 * and for initialization code.
	 */
	for (s = sechdrs; s < sechdrs_end; ++s) {
	for (s = sechdrs; s < sechdrs_end; ++s, ++i) {
		if (strcmp(".plt", secstrings + s->sh_name) == 0)
			mod->arch.core.plt = s;
			mod->arch.core.plt_shndx = i;
		else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
			mod->arch.init.plt = s;
			mod->arch.init.plt_shndx = i;
		else if (s->sh_type == SHT_SYMTAB)
			syms = (Elf32_Sym *)s->sh_addr;
	}

	if (!mod->arch.core.plt || !mod->arch.init.plt) {
	if (!mod->arch.core.plt_shndx || !mod->arch.init.plt_shndx) {
		pr_err("%s: module PLT section(s) missing\n", mod->name);
		return -ENOEXEC;
	}
@@ -239,21 +244,23 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
						numrels, s->sh_info);
	}

	mod->arch.core.plt->sh_type = SHT_NOBITS;
	mod->arch.core.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
	mod->arch.core.plt->sh_addralign = L1_CACHE_BYTES;
	mod->arch.core.plt->sh_size = round_up(core_plts * PLT_ENT_SIZE,
	core_pltsec = sechdrs + mod->arch.core.plt_shndx;
	core_pltsec->sh_type = SHT_NOBITS;
	core_pltsec->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
	core_pltsec->sh_addralign = L1_CACHE_BYTES;
	core_pltsec->sh_size = round_up(core_plts * PLT_ENT_SIZE,
					sizeof(struct plt_entries));
	mod->arch.core.plt_count = 0;

	mod->arch.init.plt->sh_type = SHT_NOBITS;
	mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
	mod->arch.init.plt->sh_addralign = L1_CACHE_BYTES;
	mod->arch.init.plt->sh_size = round_up(init_plts * PLT_ENT_SIZE,
	init_pltsec = sechdrs + mod->arch.init.plt_shndx;
	init_pltsec->sh_type = SHT_NOBITS;
	init_pltsec->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
	init_pltsec->sh_addralign = L1_CACHE_BYTES;
	init_pltsec->sh_size = round_up(init_plts * PLT_ENT_SIZE,
					sizeof(struct plt_entries));
	mod->arch.init.plt_count = 0;

	pr_debug("%s: plt=%x, init.plt=%x\n", __func__,
		 mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size);
		 core_pltsec->sh_size, init_pltsec->sh_size);
	return 0;
}
+2 −2
Original line number Diff line number Diff line
@@ -142,7 +142,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
			if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) &&
			    (offset <= (s32)0xfe000000 ||
			     offset >= (s32)0x02000000))
				offset = get_module_plt(module, loc,
				offset = get_module_plt(module, sechdrs, loc,
							offset + loc + 8)
					 - loc - 8;

@@ -265,7 +265,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
			if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) &&
			    (offset <= (s32)0xff000000 ||
			     offset >= (s32)0x01000000))
				offset = get_module_plt(module, loc,
				offset = get_module_plt(module, sechdrs, loc,
							offset + loc + 4)
					 - loc - 4;