128 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 | |
| From: Tim Chen <tim.c.chen@linux.intel.com>
 | |
| Date: Tue, 7 Nov 2017 13:52:42 -0800
 | |
| Subject: [PATCH] x86/mm: Only set IBPB when the new thread cannot ptrace
 | |
|  current thread
 | |
| MIME-Version: 1.0
 | |
| Content-Type: text/plain; charset=UTF-8
 | |
| Content-Transfer-Encoding: 8bit
 | |
| 
 | |
| 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: Tim Chen <tim.c.chen@linux.intel.com>
 | |
| Signed-off-by: Andy Whitcroft <apw@canonical.com>
 | |
| Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
 | |
| (cherry picked from commit 65941af723059ffeeca269b99ab51b3c9e320751)
 | |
| Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
 | |
| ---
 | |
|  include/linux/ptrace.h |  6 ++++++
 | |
|  arch/x86/mm/tlb.c      |  5 ++++-
 | |
|  kernel/ptrace.c        | 18 ++++++++++++++----
 | |
|  3 files changed, 24 insertions(+), 5 deletions(-)
 | |
| 
 | |
| diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
 | |
| index 0e5fcc11b1b8..d6afefd5465b 100644
 | |
| --- a/include/linux/ptrace.h
 | |
| +++ b/include/linux/ptrace.h
 | |
| @@ -63,12 +63,15 @@ 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
 | |
| @@ -86,6 +89,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 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/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
 | |
| index bb3ded3a4e5f..301e6efbc514 100644
 | |
| --- a/arch/x86/mm/tlb.c
 | |
| +++ b/arch/x86/mm/tlb.c
 | |
| @@ -6,6 +6,7 @@
 | |
|  #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>
 | |
| @@ -219,7 +220,9 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
 | |
|  		u16 new_asid;
 | |
|  		bool need_flush;
 | |
|  
 | |
| -		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);
 | |
|  
 | |
|  		if (IS_ENABLED(CONFIG_VMAP_STACK)) {
 | |
| diff --git a/kernel/ptrace.c b/kernel/ptrace.c
 | |
| index 60f356d91060..f2f0f1aeabaf 100644
 | |
| --- a/kernel/ptrace.c
 | |
| +++ b/kernel/ptrace.c
 | |
| @@ -268,9 +268,10 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
 | |
|  }
 | |
|  
 | |
|  /* 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;
 | |
|  	kuid_t caller_uid;
 | |
|  	kgid_t caller_gid;
 | |
| @@ -290,7 +291,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 | |
|  	 */
 | |
|  
 | |
|  	/* Don't let security modules deny introspection */
 | |
| -	if (same_thread_group(task, current))
 | |
| +	if (same_thread_group(task, cur))
 | |
|  		return 0;
 | |
|  	rcu_read_lock();
 | |
|  	if (mode & PTRACE_MODE_FSCREDS) {
 | |
| @@ -328,7 +329,16 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 | |
|  	     !ptrace_has_cap(mm->user_ns, mode)))
 | |
|  	    return -EPERM;
 | |
|  
 | |
| -	return security_ptrace_access_check(task, mode);
 | |
| +	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);
 | |
|  }
 | |
|  
 | |
|  bool ptrace_may_access(struct task_struct *task, unsigned int mode)
 | |
| -- 
 | |
| 2.14.2
 | |
| 
 | 
