[1/3] Revert "x86/mm: Only set IBPB when the new thread cannot ptrace current thread"

Message ID 1522907497-14743-2-git-send-email-tyhicks@canonical.com
State New
Headers show
Series
  • Fix deadlock on task switches with new microcode
Related show

Commit Message

Tyler Hicks April 5, 2018, 5:51 a.m.
BugLink: https://bugs.launchpad.net/bugs/1759920

This reverts commit 96d520d0fd4994643216f30fe91eea770ba934bc.

Using a ptrace access check in the middle of a task switch was causing
a hard lockup in some cases when the old task was confined by AppArmor.
If the AppArmor policy for the the old task didn't allow the task to
ptrace the new task, AppArmor would attempt to emit an audit message and
deadlock on the task's pi_lock would occur. The fix is to revert this
change and go with upstream's implementation that uses the task's
dumpable state to determine if IBPB should be used.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
---
 arch/x86/mm/tlb.c      |  5 +----
 include/linux/ptrace.h |  6 ------
 kernel/ptrace.c        | 18 ++++--------------
 3 files changed, 5 insertions(+), 24 deletions(-)

Patch

diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 6365f76..fdcfa70 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -6,7 +6,6 @@ 
 #include <linux/interrupt.h>
 #include <linux/export.h>
 #include <linux/cpu.h>
-#include <linux/ptrace.h>
 
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
@@ -220,9 +219,7 @@  void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
 		u16 new_asid;
 		bool need_flush;
 
-		/* Null tsk means switching to kernel, so that's safe */
-		if (ibpb_inuse && tsk &&
-			___ptrace_may_access(tsk, current, PTRACE_MODE_IBPB))
+		if (ibpb_inuse && boot_cpu_has(X86_FEATURE_SPEC_CTRL))
 			native_wrmsrl(MSR_IA32_PRED_CMD, FEATURE_SET_IBPB);
 
 		if (IS_ENABLED(CONFIG_VMAP_STACK)) {
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index d6afefd..0e5fcc1 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -63,15 +63,12 @@  extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
 #define PTRACE_MODE_NOAUDIT	0x04
 #define PTRACE_MODE_FSCREDS 0x08
 #define PTRACE_MODE_REALCREDS 0x10
-#define PTRACE_MODE_NOACCESS_CHK 0x20
 
 /* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */
 #define PTRACE_MODE_READ_FSCREDS (PTRACE_MODE_READ | PTRACE_MODE_FSCREDS)
 #define PTRACE_MODE_READ_REALCREDS (PTRACE_MODE_READ | PTRACE_MODE_REALCREDS)
 #define PTRACE_MODE_ATTACH_FSCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS)
 #define PTRACE_MODE_ATTACH_REALCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS)
-#define PTRACE_MODE_IBPB (PTRACE_MODE_ATTACH | PTRACE_MODE_NOAUDIT \
-			| PTRACE_MODE_NOACCESS_CHK | PTRACE_MODE_REALCREDS)
 
 /**
  * ptrace_may_access - check whether the caller is permitted to access
@@ -89,9 +86,6 @@  extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
  */
 extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
 
-extern int ___ptrace_may_access(struct task_struct *cur, struct task_struct *task,
-	unsigned int mode);
-
 static inline int ptrace_reparented(struct task_struct *child)
 {
 	return !same_thread_group(child->real_parent, child->parent);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index f2f0f1a..60f356d 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -268,10 +268,9 @@  static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
 }
 
 /* Returns 0 on success, -errno on denial. */
-int ___ptrace_may_access(struct task_struct *cur, struct task_struct *task,
-		unsigned int mode)
+static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
-	const struct cred *cred = __task_cred(cur), *tcred;
+	const struct cred *cred = current_cred(), *tcred;
 	struct mm_struct *mm;
 	kuid_t caller_uid;
 	kgid_t caller_gid;
@@ -291,7 +290,7 @@  int ___ptrace_may_access(struct task_struct *cur, struct task_struct *task,
 	 */
 
 	/* Don't let security modules deny introspection */
-	if (same_thread_group(task, cur))
+	if (same_thread_group(task, current))
 		return 0;
 	rcu_read_lock();
 	if (mode & PTRACE_MODE_FSCREDS) {
@@ -329,16 +328,7 @@  int ___ptrace_may_access(struct task_struct *cur, struct task_struct *task,
 	     !ptrace_has_cap(mm->user_ns, mode)))
 	    return -EPERM;
 
-	if (!(mode & PTRACE_MODE_NOACCESS_CHK))
-		return security_ptrace_access_check(task, mode);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(___ptrace_may_access);
-
-static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
-{
-	return ___ptrace_may_access(current, task, mode);
+	return security_ptrace_access_check(task, mode);
 }
 
 bool ptrace_may_access(struct task_struct *task, unsigned int mode)