lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Mon, 27 Jul 2015 17:50:36 +0200
From:	Torsten Duwe <duwe@....de>
To:	Anton Blanchard <anton@...ibm.com>
Cc:	Benjamin Herrenschmidt <benh@...nel.crashing.org>,
	Michael Ellerman <mpe@...erman.id.au>,
	Jiri Kosina <jkosina@...e.com>, linuxppc-dev@...ts.ozlabs.org,
	linux-kernel@...r.kernel.org
Subject: RFC: Kernel Live Patching for ppc64le (ABIv2)

Here is my approach to handle ABIv2 local calls that naturally
become global when passing through KLP.

On ppc64le a call is either local within the same module, and the
TOC pointer is neither saved nor restored by the caller, or it is a 
global call that passes over a TOC-saving trampoline and the next
instruction after the bl restores it. The problem I'm struggling with
is the case where KLP redirects a local call into the newly-loaded
module, making it global. I have considered and discarded some
solutions, but have not detected a flaw in this one so far ;-)

GCC adds a NOP after every function call that can be patched by the
module linker to restore the TOC; the module linker also generates
the matching trampolines. So, if I see the restore instruction, as
generated by the module linker, I assume the call already is global
and takes care of the caller's TOC. KLP can simply change the call
into the new functions' global entry.

Should it be a local call that passes through ftrace_caller (where
klp_ftrace_handler registers itself), I add a small stack frame
that restores the TOC on return. This way it can be done on a per-
thread basis to support various consistency models.

Please skim over this patch and tell me if you see any problems.
(This is on top of my ftrace with regs series, which probably needs another
iteration)

Signed-off-by: Torsten Duwe <duwe@...e.de>


diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 4768104..57af111 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -1191,8 +1191,29 @@ _GLOBAL(ftrace_caller)
 2:	// Here we have our proper TOC ptr in R2,
 	// and the one we need to restore on return in r0.
 
-	ld	r12, 16(r1)	// get caller's adress
+	ld	r12, LRSAVE(r1)	// get caller's adress
+	// Is there a TOC restore insn?
+	std	r11,-8(r1)
+	std	r12,-16(r1)
+	lwz	r12,0(r12)
+	lis	r11,0xe841	// "ld r2,TOCSAVE(r1)"
+	li	r11,TOCSAVE
+	cmpd	r12,r11
+	ld	r11,-8(r1)
+	ld	r12,-16(r1)
+	beq	4f
 
+	// TODO: test if it's really a NOP. What if not?
+
+	// If no TOC restore insn, then it was a local call and
+	// the callee's TOC needs to be restored as caller's TOC
+	// in case of live patching.
+	std	r0,TOCSAVE(r1)
+	stdu	r1,-32(r1)	// open new mini stack frame
+	LOAD_REG_IMMEDIATE(r11,KLP_return_helper)
+	std	r11,LRSAVE(r1)
+	ld	r11,24(r1)	// restore again, from -8(r1+32)
+4:
 	stdu	r1,-SWITCH_FRAME_SIZE(r1)
 
 	std     r12, _LINK(r1)
@@ -1265,6 +1286,23 @@ _GLOBAL(ftrace_stub)
 	nop
 .localentry ftrace_stub,.-ftrace_stub	
 	blr
+
+/* Helper functions for local calls that are becoming global
+   due to live patching.
+   We can't simply patch the NOP after the original call,
+   because, depending on the consistency model, some kernel
+   threads may still have called the original, local function
+   *without* saving their TOC in the respective stack frame slot,
+   so the decision is made per-thread during function return by
+   maybe inserting a KLP_return_helper frame or not.
+*/
+KLP_return_helper:
+	ld	r0,LRSAVE(r1)	// get the real return address
+	addi r1, r1, 32		// destroy this stack frame
+	ld	r2,TOCSAVE(r1)	// restore TOC
+	mtlr	r0
+	blr
+
 #else
 _GLOBAL_TOC(_mcount)
 	/* Taken from output of objdump from lib64/glibc */
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ