Skip to content

Commit c3710ee

Browse files
BenjaminGrayNp1mpe
authored andcommitted
powerpc/code-patching: Use dedicated memory routines for patching
The patching page set up as a writable alias may be in quadrant 0 (userspace) if the temporary mm path is used. This causes sanitiser failures if so. Sanitiser failures also occur on the non-mm path because the plain memset family is instrumented, and KASAN treats the patching window as poisoned. Introduce locally defined patch_* variants of memset that perform an uninstrumented lower level set, as well as detecting write errors like the original single patch variant does. copy_to_user() is not correct here, as the PTE makes it a proper kernel page (the EAA is privileged access only, RW). It just happens to be in quadrant 0 because that's the hardware's mechanism for using the current PID vs PID 0 in translations. Importantly, it's incorrect to allow user page accesses. Now that the patching memsets are used, we also propagate a failure up to the caller as the single patch variant does. Signed-off-by: Benjamin Gray <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://msgid.link/[email protected]
1 parent c5ef5e3 commit c3710ee

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

arch/powerpc/lib/code-patching.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,32 @@ int patch_instruction(u32 *addr, ppc_inst_t instr)
372372
}
373373
NOKPROBE_SYMBOL(patch_instruction);
374374

375+
static int patch_memset64(u64 *addr, u64 val, size_t count)
376+
{
377+
for (u64 *end = addr + count; addr < end; addr++)
378+
__put_kernel_nofault(addr, &val, u64, failed);
379+
380+
return 0;
381+
382+
failed:
383+
return -EPERM;
384+
}
385+
386+
static int patch_memset32(u32 *addr, u32 val, size_t count)
387+
{
388+
for (u32 *end = addr + count; addr < end; addr++)
389+
__put_kernel_nofault(addr, &val, u32, failed);
390+
391+
return 0;
392+
393+
failed:
394+
return -EPERM;
395+
}
396+
375397
static int __patch_instructions(u32 *patch_addr, u32 *code, size_t len, bool repeat_instr)
376398
{
377399
unsigned long start = (unsigned long)patch_addr;
400+
int err;
378401

379402
/* Repeat instruction */
380403
if (repeat_instr) {
@@ -383,19 +406,19 @@ static int __patch_instructions(u32 *patch_addr, u32 *code, size_t len, bool rep
383406
if (ppc_inst_prefixed(instr)) {
384407
u64 val = ppc_inst_as_ulong(instr);
385408

386-
memset64((u64 *)patch_addr, val, len / 8);
409+
err = patch_memset64((u64 *)patch_addr, val, len / 8);
387410
} else {
388411
u32 val = ppc_inst_val(instr);
389412

390-
memset32(patch_addr, val, len / 4);
413+
err = patch_memset32(patch_addr, val, len / 4);
391414
}
392415
} else {
393-
memcpy(patch_addr, code, len);
416+
err = copy_to_kernel_nofault(patch_addr, code, len);
394417
}
395418

396419
smp_wmb(); /* smp write barrier */
397420
flush_icache_range(start, start + len);
398-
return 0;
421+
return err;
399422
}
400423

401424
/*

0 commit comments

Comments
 (0)