mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 20:46:48 +02:00
arm64: Reject modules with internal alternative callbacks
During module loading, check if a callback function used by the alternatives specified in the '.altinstruction' ELF section (if present) is located in core kernel .text. If not fail module loading before callback is called. Reported-by: Fanqin Cui <cuifq1@chinatelecom.cn> Closes: https://lore.kernel.org/all/20250807072700.348514-1-fanqincui@163.com/ Signed-off-by: Adrian Barnaś <abarnas@google.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org> [will: Folded in 'noinstr' tweak from Mark] Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
6d4a0fbd34
commit
8e8ae78896
|
|
@ -26,9 +26,12 @@ void __init apply_alternatives_all(void);
|
|||
bool alternative_is_applied(u16 cpucap);
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
void apply_alternatives_module(void *start, size_t length);
|
||||
int apply_alternatives_module(void *start, size_t length);
|
||||
#else
|
||||
static inline void apply_alternatives_module(void *start, size_t length) { }
|
||||
static inline int apply_alternatives_module(void *start, size_t length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void alt_cb_patch_nops(struct alt_instr *alt, __le32 *origptr,
|
||||
|
|
|
|||
|
|
@ -139,9 +139,9 @@ static noinstr void clean_dcache_range_nopatch(u64 start, u64 end)
|
|||
} while (cur += d_size, cur < end);
|
||||
}
|
||||
|
||||
static void __apply_alternatives(const struct alt_region *region,
|
||||
bool is_module,
|
||||
unsigned long *cpucap_mask)
|
||||
static int __apply_alternatives(const struct alt_region *region,
|
||||
bool is_module,
|
||||
unsigned long *cpucap_mask)
|
||||
{
|
||||
struct alt_instr *alt;
|
||||
__le32 *origptr, *updptr;
|
||||
|
|
@ -166,10 +166,13 @@ static void __apply_alternatives(const struct alt_region *region,
|
|||
updptr = is_module ? origptr : lm_alias(origptr);
|
||||
nr_inst = alt->orig_len / AARCH64_INSN_SIZE;
|
||||
|
||||
if (ALT_HAS_CB(alt))
|
||||
if (ALT_HAS_CB(alt)) {
|
||||
alt_cb = ALT_REPL_PTR(alt);
|
||||
else
|
||||
if (is_module && !core_kernel_text((unsigned long)alt_cb))
|
||||
return -ENOEXEC;
|
||||
} else {
|
||||
alt_cb = patch_alternative;
|
||||
}
|
||||
|
||||
alt_cb(alt, origptr, updptr, nr_inst);
|
||||
|
||||
|
|
@ -193,6 +196,8 @@ static void __apply_alternatives(const struct alt_region *region,
|
|||
bitmap_and(applied_alternatives, applied_alternatives,
|
||||
system_cpucaps, ARM64_NCAPS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init apply_alternatives_vdso(void)
|
||||
|
|
@ -277,7 +282,7 @@ void __init apply_boot_alternatives(void)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
void apply_alternatives_module(void *start, size_t length)
|
||||
int apply_alternatives_module(void *start, size_t length)
|
||||
{
|
||||
struct alt_region region = {
|
||||
.begin = start,
|
||||
|
|
@ -287,7 +292,7 @@ void apply_alternatives_module(void *start, size_t length)
|
|||
|
||||
bitmap_fill(all_capabilities, ARM64_NCAPS);
|
||||
|
||||
__apply_alternatives(®ion, true, &all_capabilities[0]);
|
||||
return __apply_alternatives(®ion, true, &all_capabilities[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -489,8 +489,13 @@ int module_finalize(const Elf_Ehdr *hdr,
|
|||
int ret;
|
||||
|
||||
s = find_section(hdr, sechdrs, ".altinstructions");
|
||||
if (s)
|
||||
apply_alternatives_module((void *)s->sh_addr, s->sh_size);
|
||||
if (s) {
|
||||
ret = apply_alternatives_module((void *)s->sh_addr, s->sh_size);
|
||||
if (ret < 0) {
|
||||
pr_err("module %s: error occurred when applying alternatives\n", me->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (scs_is_dynamic()) {
|
||||
s = find_section(hdr, sechdrs, ".init.eh_frame");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user