aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2012-01-03 12:25:15 -0500
committerEric Paris <eparis@redhat.com>2012-01-05 18:53:00 -0500
commit69f594a38967f4540ce7a29b3fd214e68a8330bd (patch)
treedff25b5f5ef0736fb63b08729bec4ff57062c13f
parentf1c84dae0ecc51aa35c81f19a0ebcd6c0921ddcb (diff)
ptrace: do not audit capability check when outputing /proc/pid/stat
Reading /proc/pid/stat of another process checks if one has ptrace permissions on that process. If one does have permissions it outputs some data about the process which might have security and attack implications. If the current task does not have ptrace permissions the read still works, but those fields are filled with inocuous (0) values. Since this check and a subsequent denial is not a violation of the security policy we should not audit such denials. This can be quite useful to removing ptrace broadly across a system without flooding the logs when ps is run or something which harmlessly walks proc. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Serge E. Hallyn <serge.hallyn@canonical.com>
-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);