From: Michael Ellerman Date: Tue, 19 Jul 2016 04:48:31 +0000 (+1000) Subject: powerpc/modules: Never restore r2 for a mprofile-kernel style mcount() call X-Git-Tag: v4.14-rc1~2761^2~13 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=31278b17a0dfed3014786b623fd07ee110b801da;p=platform%2Fkernel%2Flinux-rpi.git powerpc/modules: Never restore r2 for a mprofile-kernel style mcount() call In the module loader we process relocations, and for long jumps we generate trampolines (aka stubs). At the call site for one of these trampolines we usually need to generate a load instruction to restore the TOC pointer into r2. There is one exception however, which is calls to mcount() using the mprofile-kernel ABI, they handle the TOC inside the stub, and so for them we do not generate a TOC load. The bug is in how the code in restore_r2() decides if it needs to generate the TOC load. It does so by looking for a nop following the branch, and if it sees a nop, it replaces it with the load. In general the compiler has no reason to generate a nop following the mcount() call and so that check works OK. However if we combine a jump label at the start of a function, with an early return, such that GCC applies the shrink-wrapping optimisation, we can then end up with an mcount call followed immediately by a nop. However the nop is not there for a TOC load, it is for the jump label. That confuses restore_r2() into replacing the jump label nop with a TOC load, which in turn confuses ftrace into replacing the mcount call with a b +8 (fixed in the previous commit). The end result is we jump over the jump label, which if it was supposed to return means we incorrectly run the body of the function. We have seen this in practice with some yet-to-be-merged patches that use jump labels more extensively. The fix is relatively simple, in restore_r2() we check for an mprofile-kernel style mcount() call first, before looking for the presence of a nop. Fixes: 153086644fd1 ("powerpc/ftrace: Add support for -mprofile-kernel ftrace ABI") Signed-off-by: Michael Ellerman --- diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index f703f34..183368e 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -494,9 +494,10 @@ static bool is_early_mcount_callsite(u32 *instruction) restore r2. */ static int restore_r2(u32 *instruction, struct module *me) { + if (is_early_mcount_callsite(instruction - 1)) + return 1; + if (*instruction != PPC_INST_NOP) { - if (is_early_mcount_callsite(instruction - 1)) - return 1; pr_err("%s: Expect noop after relocate, got %08x\n", me->name, *instruction); return 0;