aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c50
1 files changed, 35 insertions, 15 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 1708b1e2972d..dc7ab65f3b36 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -22,6 +22,7 @@
22#include <linux/syscalls.h> 22#include <linux/syscalls.h>
23#include <linux/uaccess.h> 23#include <linux/uaccess.h>
24#include <linux/regset.h> 24#include <linux/regset.h>
25#include <linux/hw_breakpoint.h>
25 26
26 27
27/* 28/*
@@ -134,21 +135,24 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
134 return 0; 135 return 0;
135 rcu_read_lock(); 136 rcu_read_lock();
136 tcred = __task_cred(task); 137 tcred = __task_cred(task);
137 if ((cred->uid != tcred->euid || 138 if (cred->user->user_ns == tcred->user->user_ns &&
138 cred->uid != tcred->suid || 139 (cred->uid == tcred->euid &&
139 cred->uid != tcred->uid || 140 cred->uid == tcred->suid &&
140 cred->gid != tcred->egid || 141 cred->uid == tcred->uid &&
141 cred->gid != tcred->sgid || 142 cred->gid == tcred->egid &&
142 cred->gid != tcred->gid) && 143 cred->gid == tcred->sgid &&
143 !capable(CAP_SYS_PTRACE)) { 144 cred->gid == tcred->gid))
144 rcu_read_unlock(); 145 goto ok;
145 return -EPERM; 146 if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE))
146 } 147 goto ok;
148 rcu_read_unlock();
149 return -EPERM;
150ok:
147 rcu_read_unlock(); 151 rcu_read_unlock();
148 smp_rmb(); 152 smp_rmb();
149 if (task->mm) 153 if (task->mm)
150 dumpable = get_dumpable(task->mm); 154 dumpable = get_dumpable(task->mm);
151 if (!dumpable && !capable(CAP_SYS_PTRACE)) 155 if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE))
152 return -EPERM; 156 return -EPERM;
153 157
154 return security_ptrace_access_check(task, mode); 158 return security_ptrace_access_check(task, mode);
@@ -163,7 +167,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
163 return !err; 167 return !err;
164} 168}
165 169
166int ptrace_attach(struct task_struct *task) 170static int ptrace_attach(struct task_struct *task)
167{ 171{
168 int retval; 172 int retval;
169 173
@@ -198,7 +202,7 @@ int ptrace_attach(struct task_struct *task)
198 goto unlock_tasklist; 202 goto unlock_tasklist;
199 203
200 task->ptrace = PT_PTRACED; 204 task->ptrace = PT_PTRACED;
201 if (capable(CAP_SYS_PTRACE)) 205 if (task_ns_capable(task, CAP_SYS_PTRACE))
202 task->ptrace |= PT_PTRACE_CAP; 206 task->ptrace |= PT_PTRACE_CAP;
203 207
204 __ptrace_link(task, current); 208 __ptrace_link(task, current);
@@ -219,7 +223,7 @@ out:
219 * Performs checks and sets PT_PTRACED. 223 * Performs checks and sets PT_PTRACED.
220 * Should be used by all ptrace implementations for PTRACE_TRACEME. 224 * Should be used by all ptrace implementations for PTRACE_TRACEME.
221 */ 225 */
222int ptrace_traceme(void) 226static int ptrace_traceme(void)
223{ 227{
224 int ret = -EPERM; 228 int ret = -EPERM;
225 229
@@ -293,7 +297,7 @@ static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
293 return false; 297 return false;
294} 298}
295 299
296int ptrace_detach(struct task_struct *child, unsigned int data) 300static int ptrace_detach(struct task_struct *child, unsigned int data)
297{ 301{
298 bool dead = false; 302 bool dead = false;
299 303
@@ -876,3 +880,19 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
876 return ret; 880 return ret;
877} 881}
878#endif /* CONFIG_COMPAT */ 882#endif /* CONFIG_COMPAT */
883
884#ifdef CONFIG_HAVE_HW_BREAKPOINT
885int ptrace_get_breakpoints(struct task_struct *tsk)
886{
887 if (atomic_inc_not_zero(&tsk->ptrace_bp_refcnt))
888 return 0;
889
890 return -1;
891}
892
893void ptrace_put_breakpoints(struct task_struct *tsk)
894{
895 if (atomic_dec_and_test(&tsk->ptrace_bp_refcnt))
896 flush_ptrace_hw_breakpoint(tsk);
897}
898#endif /* CONFIG_HAVE_HW_BREAKPOINT */