Skip to content

Commit 8734b41

Browse files
ruscurmpe
authored andcommitted
powerpc/module_64: Fix livepatching for RO modules
Livepatching a loaded module involves applying relocations through apply_relocate_add(), which attempts to write to read-only memory when CONFIG_STRICT_MODULE_RWX=y. Work around this by performing these writes through the text poke area by using patch_instruction(). R_PPC_REL24 is the only relocation type generated by the kpatch-build userspace tool or klp-convert kernel tree that I observed applying a relocation to a post-init module. A more comprehensive solution is planned, but using patch_instruction() for R_PPC_REL24 on should serve as a sufficient fix. This does have a performance impact, I observed ~15% overhead in module_load() on POWER8 bare metal with checksum verification off. Fixes: c35717c ("powerpc: Set ARCH_HAS_STRICT_MODULE_RWX") Cc: [email protected] # v5.14+ Reported-by: Joe Lawrence <[email protected]> Signed-off-by: Russell Currey <[email protected]> Tested-by: Joe Lawrence <[email protected]> [mpe: Check return codes from patch_instruction()] Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 3dc709e commit 8734b41

File tree

1 file changed

+34
-8
lines changed

1 file changed

+34
-8
lines changed

arch/powerpc/kernel/module_64.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -422,11 +422,17 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,
422422
const char *name)
423423
{
424424
long reladdr;
425+
func_desc_t desc;
426+
int i;
425427

426428
if (is_mprofile_ftrace_call(name))
427429
return create_ftrace_stub(entry, addr, me);
428430

429-
memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns));
431+
for (i = 0; i < sizeof(ppc64_stub_insns) / sizeof(u32); i++) {
432+
if (patch_instruction(&entry->jump[i],
433+
ppc_inst(ppc64_stub_insns[i])))
434+
return 0;
435+
}
430436

431437
/* Stub uses address relative to r2. */
432438
reladdr = (unsigned long)entry - my_r2(sechdrs, me);
@@ -437,10 +443,24 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,
437443
}
438444
pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr);
439445

440-
entry->jump[0] |= PPC_HA(reladdr);
441-
entry->jump[1] |= PPC_LO(reladdr);
442-
entry->funcdata = func_desc(addr);
443-
entry->magic = STUB_MAGIC;
446+
if (patch_instruction(&entry->jump[0],
447+
ppc_inst(entry->jump[0] | PPC_HA(reladdr))))
448+
return 0;
449+
450+
if (patch_instruction(&entry->jump[1],
451+
ppc_inst(entry->jump[1] | PPC_LO(reladdr))))
452+
return 0;
453+
454+
// func_desc_t is 8 bytes if ABIv2, else 16 bytes
455+
desc = func_desc(addr);
456+
for (i = 0; i < sizeof(func_desc_t) / sizeof(u32); i++) {
457+
if (patch_instruction(((u32 *)&entry->funcdata) + i,
458+
ppc_inst(((u32 *)(&desc))[i])))
459+
return 0;
460+
}
461+
462+
if (patch_instruction(&entry->magic, ppc_inst(STUB_MAGIC)))
463+
return 0;
444464

445465
return 1;
446466
}
@@ -495,8 +515,11 @@ static int restore_r2(const char *name, u32 *instruction, struct module *me)
495515
me->name, *instruction, instruction);
496516
return 0;
497517
}
518+
498519
/* ld r2,R2_STACK_OFFSET(r1) */
499-
*instruction = PPC_INST_LD_TOC;
520+
if (patch_instruction(instruction, ppc_inst(PPC_INST_LD_TOC)))
521+
return 0;
522+
500523
return 1;
501524
}
502525

@@ -636,9 +659,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
636659
}
637660

638661
/* Only replace bits 2 through 26 */
639-
*(uint32_t *)location
640-
= (*(uint32_t *)location & ~0x03fffffc)
662+
value = (*(uint32_t *)location & ~0x03fffffc)
641663
| (value & 0x03fffffc);
664+
665+
if (patch_instruction((u32 *)location, ppc_inst(value)))
666+
return -EFAULT;
667+
642668
break;
643669

644670
case R_PPC64_REL64:

0 commit comments

Comments
 (0)