aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/array.c2
-rw-r--r--include/linux/ptrace.h5
-rw-r--r--kernel/ptrace.c12
-rw-r--r--security/selinux/hooks.c2
4 files changed, 15 insertions, 6 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 3a1dafd228d1..ddffd7a88b97 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -380,7 +380,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
380 380
381 state = *get_task_state(task); 381 state = *get_task_state(task);
382 vsize = eip = esp = 0; 382 vsize = eip = esp = 0;
383 permitted = ptrace_may_access(task, PTRACE_MODE_READ); 383 permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT);
384 mm = get_task_mm(task); 384 mm = get_task_mm(task);
385 if (mm) { 385 if (mm) {
386 vsize = task_vsize(mm); 386 vsize = task_vsize(mm);
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 800f113bea66..a27e56ca41a4 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -127,8 +127,9 @@ extern void __ptrace_link(struct task_struct *child,
127 struct task_struct *new_parent); 127 struct task_struct *new_parent);
128extern void __ptrace_unlink(struct task_struct *child); 128extern void __ptrace_unlink(struct task_struct *child);
129extern void exit_ptrace(struct task_struct *tracer); 129extern void exit_ptrace(struct task_struct *tracer);
130#define PTRACE_MODE_READ 1 130#define PTRACE_MODE_READ 0x01
131#define PTRACE_MODE_ATTACH 2 131#define PTRACE_MODE_ATTACH 0x02
132#define PTRACE_MODE_NOAUDIT 0x04
132/* Returns 0 on success, -errno on denial. */ 133/* Returns 0 on success, -errno on denial. */
133extern int __ptrace_may_access(struct task_struct *task, unsigned int mode); 134extern int __ptrace_may_access(struct task_struct *task, unsigned int mode);
134/* Returns true on success, false on denial. */ 135/* Returns true on success, false on denial. */
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 210bbf045ee9..c890ac9a7962 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -161,6 +161,14 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state)
161 return ret; 161 return ret;
162} 162}
163 163
164static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
165{
166 if (mode & PTRACE_MODE_NOAUDIT)
167 return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE);
168 else
169 return has_ns_capability(current, ns, CAP_SYS_PTRACE);
170}
171
164int __ptrace_may_access(struct task_struct *task, unsigned int mode) 172int __ptrace_may_access(struct task_struct *task, unsigned int mode)
165{ 173{
166 const struct cred *cred = current_cred(), *tcred; 174 const struct cred *cred = current_cred(), *tcred;
@@ -187,7 +195,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
187 cred->gid == tcred->sgid && 195 cred->gid == tcred->sgid &&
188 cred->gid == tcred->gid)) 196 cred->gid == tcred->gid))
189 goto ok; 197 goto ok;
190 if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE)) 198 if (ptrace_has_cap(tcred->user->user_ns, mode))
191 goto ok; 199 goto ok;
192 rcu_read_unlock(); 200 rcu_read_unlock();
193 return -EPERM; 201 return -EPERM;
@@ -196,7 +204,7 @@ ok:
196 smp_rmb(); 204 smp_rmb();
197 if (task->mm) 205 if (task->mm)
198 dumpable = get_dumpable(task->mm); 206 dumpable = get_dumpable(task->mm);
199 if (!dumpable && !ns_capable(task_user_ns(task), CAP_SYS_PTRACE)) 207 if (!dumpable && !ptrace_has_cap(task_user_ns(task), mode))
200 return -EPERM; 208 return -EPERM;
201 209
202 return security_ptrace_access_check(task, mode); 210 return security_ptrace_access_check(task, mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c9605c4a2e08..14f94cd29c80 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1809,7 +1809,7 @@ static int selinux_ptrace_access_check(struct task_struct *child,
1809 if (rc) 1809 if (rc)
1810 return rc; 1810 return rc;
1811 1811
1812 if (mode == PTRACE_MODE_READ) { 1812 if (mode & PTRACE_MODE_READ) {
1813 u32 sid = current_sid(); 1813 u32 sid = current_sid();
1814 u32 csid = task_sid(child); 1814 u32 csid = task_sid(child);
1815 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); 1815 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);