ptrace: do not audit capability check when outputing /proc/pid/stat
authorEric Paris <eparis@redhat.com>
Tue, 3 Jan 2012 17:25:15 +0000 (12:25 -0500)
committerEric Paris <eparis@redhat.com>
Thu, 5 Jan 2012 23:53:00 +0000 (18:53 -0500)
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>
fs/proc/array.c
include/linux/ptrace.h
kernel/ptrace.c
security/selinux/hooks.c

index 3a1dafd228d14c5e11b142084305e8b60161f84c..ddffd7a88b975b303dead614f713ab58a7fe4ef9 100644 (file)
@@ -380,7 +380,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
 
        state = *get_task_state(task);
        vsize = eip = esp = 0;
-       permitted = ptrace_may_access(task, PTRACE_MODE_READ);
+       permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT);
        mm = get_task_mm(task);
        if (mm) {
                vsize = task_vsize(mm);
index 800f113bea66382fd16dc28c85eeae34e44761b0..a27e56ca41a4cf2ae505e08710c88f745f476510 100644 (file)
@@ -127,8 +127,9 @@ extern void __ptrace_link(struct task_struct *child,
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
 extern void exit_ptrace(struct task_struct *tracer);
-#define PTRACE_MODE_READ   1
-#define PTRACE_MODE_ATTACH 2
+#define PTRACE_MODE_READ       0x01
+#define PTRACE_MODE_ATTACH     0x02
+#define PTRACE_MODE_NOAUDIT    0x04
 /* Returns 0 on success, -errno on denial. */
 extern int __ptrace_may_access(struct task_struct *task, unsigned int mode);
 /* Returns true on success, false on denial. */
index 210bbf045ee983697ea6c187d5d537e32ad0c779..c890ac9a796235bc22a9f0f17c28eddabd32af34 100644 (file)
@@ -161,6 +161,14 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state)
        return ret;
 }
 
+static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
+{
+       if (mode & PTRACE_MODE_NOAUDIT)
+               return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE);
+       else
+               return has_ns_capability(current, ns, CAP_SYS_PTRACE);
+}
+
 int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
        const struct cred *cred = current_cred(), *tcred;
@@ -187,7 +195,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
             cred->gid == tcred->sgid &&
             cred->gid == tcred->gid))
                goto ok;
-       if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE))
+       if (ptrace_has_cap(tcred->user->user_ns, mode))
                goto ok;
        rcu_read_unlock();
        return -EPERM;
@@ -196,7 +204,7 @@ ok:
        smp_rmb();
        if (task->mm)
                dumpable = get_dumpable(task->mm);
-       if (!dumpable && !ns_capable(task_user_ns(task), CAP_SYS_PTRACE))
+       if (!dumpable  && !ptrace_has_cap(task_user_ns(task), mode))
                return -EPERM;
 
        return security_ptrace_access_check(task, mode);
index c9605c4a2e08f3569f0efc5b8a5065ffc901c307..14f94cd29c80ce60eca1c54d31b669f4ca80f37e 100644 (file)
@@ -1809,7 +1809,7 @@ static int selinux_ptrace_access_check(struct task_struct *child,
        if (rc)
                return rc;
 
-       if (mode == PTRACE_MODE_READ) {
+       if (mode & PTRACE_MODE_READ) {
                u32 sid = current_sid();
                u32 csid = task_sid(child);
                return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);