[PATCH 1/5] selftests/powerpc: Add exec() test to check for spr sanitisation

Subsystems: kernel selftest framework, the rest

STALE3784d

6 messages, 2 authors, 2016-03-24 · open the first message on its own page

[PATCH 1/5] selftests/powerpc: Add exec() test to check for spr sanitisation

From: Cyril Bur <hidden>
Date: 2016-03-23 05:48:46

Signed-off-by: Cyril Bur <redacted>
---
 tools/testing/selftests/powerpc/syscalls/Makefile  |  3 +-
 .../testing/selftests/powerpc/syscalls/spr_exec.c  | 78 ++++++++++++++++++++++
 2 files changed, 80 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/powerpc/syscalls/spr_exec.c
diff --git a/tools/testing/selftests/powerpc/syscalls/Makefile b/tools/testing/selftests/powerpc/syscalls/Makefile
index b35c794..291ba45 100644
--- a/tools/testing/selftests/powerpc/syscalls/Makefile
+++ b/tools/testing/selftests/powerpc/syscalls/Makefile
@@ -1,10 +1,11 @@
-TEST_PROGS := ipc_unmuxed
+TEST_PROGS := ipc_unmuxed spr_exec
 
 CFLAGS += -I../../../../../usr/include
 
 all: $(TEST_PROGS)
 
 $(TEST_PROGS): ../harness.c
+spr_exec: ../utils.c
 
 include ../../lib.mk
 
diff --git a/tools/testing/selftests/powerpc/syscalls/spr_exec.c b/tools/testing/selftests/powerpc/syscalls/spr_exec.c
new file mode 100644
index 0000000..5ecd6ca
--- /dev/null
+++ b/tools/testing/selftests/powerpc/syscalls/spr_exec.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This test checks that the TAR (an SPR) is correctly sanitised across
+ * execve()
+ */
+#include <asm/cputable.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+static char *name;
+static int count;
+
+static int exec_spr(void)
+{
+	unsigned long tar;
+	char buffer[10];
+	char *args[3];
+
+	asm __volatile__(
+			"mfspr %[tar], 815"
+			: [tar] "=r" (tar)
+			);
+	/* Read TAR */
+	FAIL_IF(tar != 0);
+
+	tar = 1;
+	asm __volatile__(
+			"mtspr 815, %[tar]"
+			:
+			: [tar] "r" (tar)
+			);
+
+	FAIL_IF(sprintf(buffer, "%d", count + 1) == -1);
+	args[0] = name;
+	args[1] = buffer;
+	args[2] = NULL;
+	FAIL_IF(execve(name, args, NULL) == -1);
+
+	return 0;
+}
+
+static int exec_spr_check(void)
+{
+	unsigned long tar;
+
+	asm __volatile__(
+			"mfspr %[tar], 815;"
+			: [tar] "=r" (tar)
+			);
+	/* Read TAR */
+	FAIL_IF(tar != 0);
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	SKIP_IF(!have_hwcap2(PPC_FEATURE2_TAR));
+	name = argv[0];
+	/* Do this a few times to be sure isn't a false negative */
+	if (argc == 1 || atoi(argv[1]) < 10) {
+		if (argc > 1)
+			count = atoi(argv[1]);
+		return test_harness(exec_spr, "spr_exec");
+	} else {
+		return test_harness(exec_spr_check, "spr_exec_check");
+	}
+}
-- 
2.7.4

[PATCH 2/5] selftests/powerpc: Add fork() test to check for spr being preserved

From: Cyril Bur <hidden>
Date: 2016-03-23 05:48:44

Signed-off-by: Cyril Bur <redacted>
---
 tools/testing/selftests/powerpc/syscalls/Makefile  |  3 +-
 .../testing/selftests/powerpc/syscalls/spr_fork.c  | 78 ++++++++++++++++++++++
 2 files changed, 80 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/powerpc/syscalls/spr_fork.c
diff --git a/tools/testing/selftests/powerpc/syscalls/Makefile b/tools/testing/selftests/powerpc/syscalls/Makefile
index 291ba45..55969f3 100644
--- a/tools/testing/selftests/powerpc/syscalls/Makefile
+++ b/tools/testing/selftests/powerpc/syscalls/Makefile
@@ -1,4 +1,4 @@
-TEST_PROGS := ipc_unmuxed spr_exec
+TEST_PROGS := ipc_unmuxed spr_exec spr_fork
 
 CFLAGS += -I../../../../../usr/include
 
@@ -6,6 +6,7 @@ all: $(TEST_PROGS)
 
 $(TEST_PROGS): ../harness.c
 spr_exec: ../utils.c
+spr_fork: ../utils.c
 
 include ../../lib.mk
 
diff --git a/tools/testing/selftests/powerpc/syscalls/spr_fork.c b/tools/testing/selftests/powerpc/syscalls/spr_fork.c
new file mode 100644
index 0000000..1a351a6
--- /dev/null
+++ b/tools/testing/selftests/powerpc/syscalls/spr_fork.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This test checks that the TAR register (an SPR) is correctly preserved
+ * across a fork()
+ */
+#include <asm/cputable.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+static int fork_spr(void)
+{
+	int child_ret;
+	unsigned long tar;
+	pid_t pid;
+	int i;
+
+
+	/* Do it a few times as there is a chance that one might luckily pass */
+	i = 0;
+	while (i < 10) {
+		/* What are the odds... */
+		tar = 0x123456;
+		asm __volatile__(
+				"mtspr 815, %[tar]"
+				:
+				: [tar] "r" (tar)
+				);
+
+		pid = fork();
+		FAIL_IF(pid == -1);
+		asm __volatile__(
+				"mfspr %[tar], 815"
+				: [tar] "=r" (tar)
+				);
+
+		FAIL_IF(tar != 0x123456);
+
+		if (pid == 0)
+			exit(0);
+
+		FAIL_IF(waitpid(pid, &child_ret, 0) == -1);
+
+		/* Child haddn't exited ? */
+		FAIL_IF(!WIFEXITED(child_ret));
+
+		/* Child detected a bad tar */
+		FAIL_IF(WEXITSTATUS(child_ret));
+
+		/* Reset it */
+		tar = 0;
+		asm __volatile__(
+				"mtspr 815, %[tar]"
+				:
+				: [tar] "r" (tar)
+				);
+
+		i++;
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	SKIP_IF(!have_hwcap2(PPC_FEATURE2_TAR));
+	return test_harness(fork_spr, "spr_fork");
+}
-- 
2.7.4

[PATCH 3/5] powerpc: Fix TAR leak across exec() syscalls

From: Cyril Bur <hidden>
Date: 2016-03-23 05:48:47

Currently start_thread() doesn't sanitise TAR.

The TAR SPR register is a register that can be set and branched to, not
sanitising it presents an information leak to the new executable.

Other SPR registers such as the Performance registers used by perf (and are
managed entirely by perf) as well as the Event Based Branch (EBB) registers are
left alone by design as these fall into the same category as leaving file
descriptors open across exec(), it is up the parent thread to sanitise what it
deems necessary.

Signed-off-by: Cyril Bur <redacted>
---
 arch/powerpc/kernel/process.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index d7a9df5..56444a6 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1577,6 +1577,8 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 	current->thread.vr_state.vscr.u[3] = 0x00010000; /* Java mode disabled */
 	current->thread.vr_save_area = NULL;
 	current->thread.vrsave = 0;
+	if (cpu_has_feature(CPU_FTR_ALTIVEC))
+		mtspr(SPRN_VRSAVE, 0);
 	current->thread.used_vr = 0;
 #endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_SPE
@@ -1592,6 +1594,18 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 	current->thread.tm_texasr = 0;
 	current->thread.tm_tfiar = 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC_BOOK3S_64
+	/*
+	 * Zero out the SPRs.
+	 * Don't touch the ones use by perf, it controls them.
+	 * Don't touch the EBB regs. This falls into the same category of
+	 *   responsibly as open file descriptors across exec(), the parent should
+	 *   sanitise if it feels it would be a problem
+	 */
+	current->thread.tar = 0;
+	if (cpu_has_feature(CPU_FTR_ARCH_206))
+		mtspr(SPRN_TAR, 0);
+#endif /* CONFIG_PPC_BOOK3S_64 */
 }
 EXPORT_SYMBOL(start_thread);
 
-- 
2.7.4

[PATCH 5/5] powerpc: Preserve the SPR values across fork() syscalls

From: Cyril Bur <hidden>
Date: 2016-03-23 05:48:47

Currently copy_thread() doesn't flush SPRs to the parent thread struct.
Currently this only affects the TAR register as perf takes care of some of the
others and the remaining ones are all Event Based Branch (EBB) registers which
are cleared across fork().

Signed-off-by: Cyril Bur <redacted>
---
 arch/powerpc/kernel/process.c | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 7625976..892c76d 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1037,6 +1037,8 @@ void flush_all_to_thread(struct task_struct *tsk)
 		BUG_ON(tsk != current);
 		save_all(tsk);
 
+		save_sprs(&tsk->thread);
+
 #ifdef CONFIG_SPE
 		if (tsk->thread.regs->msr & MSR_SPE)
 			tsk->thread.spefscr = mfspr(SPRN_SPEFSCR);
-- 
2.7.4

[PATCH 4/5] powerpc: Move flush_all_to_thread() below save_sprs()

From: Cyril Bur <hidden>
Date: 2016-03-23 05:48:47

Signed-off-by: Cyril Bur <redacted>
---
 arch/powerpc/kernel/process.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 56444a6..7625976 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -511,23 +511,6 @@ void save_all(struct task_struct *tsk)
 	msr_check_and_clear(msr_all_available);
 }
 
-void flush_all_to_thread(struct task_struct *tsk)
-{
-	if (tsk->thread.regs) {
-		preempt_disable();
-		BUG_ON(tsk != current);
-		save_all(tsk);
-
-#ifdef CONFIG_SPE
-		if (tsk->thread.regs->msr & MSR_SPE)
-			tsk->thread.spefscr = mfspr(SPRN_SPEFSCR);
-#endif
-
-		preempt_enable();
-	}
-}
-EXPORT_SYMBOL(flush_all_to_thread);
-
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 void do_send_trap(struct pt_regs *regs, unsigned long address,
 		  unsigned long error_code, int signal_code, int breakpt)
@@ -1047,6 +1030,23 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 #endif
 }
 
+void flush_all_to_thread(struct task_struct *tsk)
+{
+	if (tsk->thread.regs) {
+		preempt_disable();
+		BUG_ON(tsk != current);
+		save_all(tsk);
+
+#ifdef CONFIG_SPE
+		if (tsk->thread.regs->msr & MSR_SPE)
+			tsk->thread.spefscr = mfspr(SPRN_SPEFSCR);
+#endif
+
+		preempt_enable();
+	}
+}
+EXPORT_SYMBOL(flush_all_to_thread);
+
 struct task_struct *__switch_to(struct task_struct *prev,
 	struct task_struct *new)
 {
-- 
2.7.4

Re: [PATCH 3/5] powerpc: Fix TAR leak across exec() syscalls

From: Michael Neuling <hidden>
Date: 2016-03-24 08:44:26

On Wed, 2016-03-23 at 16:47 +1100, Cyril Bur wrote:
Currently start_thread() doesn't sanitise TAR.
=20
The TAR SPR register is a register that can be set and branched to, not
sanitising it presents an information leak to the new executable.
=20
Other SPR registers such as the Performance registers used by perf (and a=
re
managed entirely by perf) as well as the Event Based Branch (EBB) registe=
rs are
left alone by design as these fall into the same category as leaving file
descriptors open across exec(), it is up the parent thread to sanitise wh=
at it
quoted hunk
deems necessary.
=20
Signed-off-by: Cyril Bur <redacted>
---
 arch/powerpc/kernel/process.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
=20
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.=
c
quoted hunk
index d7a9df5..56444a6 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1577,6 +1577,8 @@ void start_thread(struct pt_regs *regs, unsigned lo=
ng start, unsigned long sp)
 	current->thread.vr_state.vscr.u[3] =3D 0x00010000; /* Java mode disable=
d */
 	current->thread.vr_save_area =3D NULL;
 	current->thread.vrsave =3D 0;
+	if (cpu_has_feature(CPU_FTR_ALTIVEC))
+		mtspr(SPRN_VRSAVE, 0);
VRSAVE is not mentioned in the commit message.
quoted hunk
 	current->thread.used_vr =3D 0;
 #endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_SPE
@@ -1592,6 +1594,18 @@ void start_thread(struct pt_regs *regs, unsigned l=
ong start, unsigned long sp)
 	current->thread.tm_texasr =3D 0;
 	current->thread.tm_tfiar =3D 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC_BOOK3S_64
+	/*
+	 * Zero out the SPRs.
+	 * Don't touch the ones use by perf, it controls them.
+	 * Don't touch the EBB regs. This falls into the same category of
+	 *   responsibly as open file descriptors across exec(), the parent sho=
uld
+	 *   sanitise if it feels it would be a problem
+	 */
+	current->thread.tar =3D 0;
+	if (cpu_has_feature(CPU_FTR_ARCH_206))
+		mtspr(SPRN_TAR, 0);
+#endif /* CONFIG_PPC_BOOK3S_64 */
 }
 EXPORT_SYMBOL(start_thread);
=20
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help