Commit 69f594a38967f4540ce7a29b3fd214e68a8330bd
1 parent
f1c84dae0e
Exists in
master
and in
20 other branches
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>
Showing 4 changed files with 15 additions and 6 deletions Side-by-side Diff
fs/proc/array.c
... | ... | @@ -380,7 +380,7 @@ |
380 | 380 | |
381 | 381 | state = *get_task_state(task); |
382 | 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 | 384 | mm = get_task_mm(task); |
385 | 385 | if (mm) { |
386 | 386 | vsize = task_vsize(mm); |
include/linux/ptrace.h
... | ... | @@ -127,8 +127,9 @@ |
127 | 127 | struct task_struct *new_parent); |
128 | 128 | extern void __ptrace_unlink(struct task_struct *child); |
129 | 129 | extern void exit_ptrace(struct task_struct *tracer); |
130 | -#define PTRACE_MODE_READ 1 | |
131 | -#define PTRACE_MODE_ATTACH 2 | |
130 | +#define PTRACE_MODE_READ 0x01 | |
131 | +#define PTRACE_MODE_ATTACH 0x02 | |
132 | +#define PTRACE_MODE_NOAUDIT 0x04 | |
132 | 133 | /* Returns 0 on success, -errno on denial. */ |
133 | 134 | extern int __ptrace_may_access(struct task_struct *task, unsigned int mode); |
134 | 135 | /* Returns true on success, false on denial. */ |
kernel/ptrace.c
... | ... | @@ -161,6 +161,14 @@ |
161 | 161 | return ret; |
162 | 162 | } |
163 | 163 | |
164 | +static 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 | + | |
164 | 172 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
165 | 173 | { |
166 | 174 | const struct cred *cred = current_cred(), *tcred; |
... | ... | @@ -187,7 +195,7 @@ |
187 | 195 | cred->gid == tcred->sgid && |
188 | 196 | cred->gid == tcred->gid)) |
189 | 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 | 199 | goto ok; |
192 | 200 | rcu_read_unlock(); |
193 | 201 | return -EPERM; |
... | ... | @@ -196,7 +204,7 @@ |
196 | 204 | smp_rmb(); |
197 | 205 | if (task->mm) |
198 | 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 | 208 | return -EPERM; |
201 | 209 | |
202 | 210 | return security_ptrace_access_check(task, mode); |
security/selinux/hooks.c
... | ... | @@ -1809,7 +1809,7 @@ |
1809 | 1809 | if (rc) |
1810 | 1810 | return rc; |
1811 | 1811 | |
1812 | - if (mode == PTRACE_MODE_READ) { | |
1812 | + if (mode & PTRACE_MODE_READ) { | |
1813 | 1813 | u32 sid = current_sid(); |
1814 | 1814 | u32 csid = task_sid(child); |
1815 | 1815 | return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); |