Commit b0c3e8bd authored by Tim Chen's avatar Tim Chen Committed by Marcelo Henrique Cerri

x86/mm: Only set IBPB when the new thread cannot ptrace current thread

CVE-2017-5753
CVE-2017-5715

To reduce overhead of setting IBPB, we only do that when
the new thread cannot ptrace the current one.  If the new
thread has ptrace capability on current thread, it is safe.
Signed-off-by: default avatarTim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: default avatarAndy Whitcroft <apw@canonical.com>
(backported from commit 294ed6288a44f78781cf33cc9de32c50630c1646)
Signed-off-by: default avatarAndy Whitcroft <apw@canonical.com>
parent 49bb7a3c
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/ptrace.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
...@@ -140,7 +141,9 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -140,7 +141,9 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
/* Stop flush ipis for the previous mm */ /* Stop flush ipis for the previous mm */
cpumask_clear_cpu(cpu, mm_cpumask(prev)); cpumask_clear_cpu(cpu, mm_cpumask(prev));
if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) /* Null tsk means switching to kernel, so that's safe */
if (boot_cpu_has(X86_FEATURE_SPEC_CTRL) && tsk &&
___ptrace_may_access(tsk, current, PTRACE_MODE_IBPB))
native_wrmsrl(MSR_IA32_PRED_CMD, FEATURE_SET_IBPB); native_wrmsrl(MSR_IA32_PRED_CMD, FEATURE_SET_IBPB);
/* Load per-mm CR4 state */ /* Load per-mm CR4 state */
......
...@@ -59,12 +59,15 @@ extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead); ...@@ -59,12 +59,15 @@ extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
#define PTRACE_MODE_NOAUDIT 0x04 #define PTRACE_MODE_NOAUDIT 0x04
#define PTRACE_MODE_FSCREDS 0x08 #define PTRACE_MODE_FSCREDS 0x08
#define PTRACE_MODE_REALCREDS 0x10 #define PTRACE_MODE_REALCREDS 0x10
#define PTRACE_MODE_NOACCESS_CHK 0x20
/* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */ /* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */
#define PTRACE_MODE_READ_FSCREDS (PTRACE_MODE_READ | PTRACE_MODE_FSCREDS) #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_READ_REALCREDS (PTRACE_MODE_READ | PTRACE_MODE_REALCREDS)
#define PTRACE_MODE_ATTACH_FSCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS) #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_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 * ptrace_may_access - check whether the caller is permitted to access
...@@ -82,6 +85,9 @@ extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead); ...@@ -82,6 +85,9 @@ 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 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) static inline int ptrace_reparented(struct task_struct *child)
{ {
return !same_thread_group(child->real_parent, child->parent); return !same_thread_group(child->real_parent, child->parent);
......
...@@ -235,9 +235,10 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) ...@@ -235,9 +235,10 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
} }
/* Returns 0 on success, -errno on denial. */ /* Returns 0 on success, -errno on denial. */
static int __ptrace_may_access(struct task_struct *task, unsigned int mode) int ___ptrace_may_access(struct task_struct *cur, struct task_struct *task,
unsigned int mode)
{ {
const struct cred *cred = current_cred(), *tcred; const struct cred *cred = __task_cred(cur), *tcred;
struct mm_struct *mm; struct mm_struct *mm;
kuid_t caller_uid; kuid_t caller_uid;
kgid_t caller_gid; kgid_t caller_gid;
...@@ -257,7 +258,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) ...@@ -257,7 +258,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
*/ */
/* Don't let security modules deny introspection */ /* Don't let security modules deny introspection */
if (same_thread_group(task, current)) if (same_thread_group(task, cur))
return 0; return 0;
rcu_read_lock(); rcu_read_lock();
if (mode & PTRACE_MODE_FSCREDS) { if (mode & PTRACE_MODE_FSCREDS) {
...@@ -295,7 +296,16 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) ...@@ -295,7 +296,16 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
!ptrace_has_cap(mm->user_ns, mode))) !ptrace_has_cap(mm->user_ns, mode)))
return -EPERM; return -EPERM;
if (!(mode & PTRACE_MODE_NOACCESS_CHK))
return security_ptrace_access_check(task, mode); 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);
} }
bool ptrace_may_access(struct task_struct *task, unsigned int mode) bool ptrace_may_access(struct task_struct *task, unsigned int mode)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment