OSDN Git Service

Yama: add additional ptrace scopes
authorKees Cook <keescook@chromium.org>
Mon, 16 Apr 2012 18:56:45 +0000 (11:56 -0700)
committerJames Morris <james.l.morris@oracle.com>
Thu, 19 Apr 2012 03:39:56 +0000 (13:39 +1000)
This expands the available Yama ptrace restrictions to include two more
modes. Mode 2 requires CAP_SYS_PTRACE for PTRACE_ATTACH, and mode 3
completely disables PTRACE_ATTACH (and locks the sysctl).

Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: James Morris <james.l.morris@oracle.com>
Documentation/security/Yama.txt
security/yama/yama_lsm.c

index a9511f1..e369de2 100644 (file)
@@ -34,7 +34,7 @@ parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still
 work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID"
 still work as root).
 
-For software that has defined application-specific relationships
+In mode 1, software that has defined application-specific relationships
 between a debugging process and its inferior (crash handlers, etc),
 prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which
 other process (and its descendents) are allowed to call PTRACE_ATTACH
@@ -46,6 +46,8 @@ restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...)
 so that any otherwise allowed process (even those in external pid namespaces)
 may attach.
 
+These restrictions do not change how ptrace via PTRACE_TRACEME operates.
+
 The sysctl settings are:
 
 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
@@ -60,6 +62,12 @@ The sysctl settings are:
     inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare
     an allowed debugger PID to call PTRACE_ATTACH on the inferior.
 
+2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace
+    with PTRACE_ATTACH.
+
+3 - no attach: no processes may use ptrace with PTRACE_ATTACH. Once set,
+    this sysctl cannot be changed to a lower value.
+
 The original children-only logic was based on the restrictions in grsecurity.
 
 ==============================================================
index 5737238..afb04cb 100644 (file)
 #include <linux/prctl.h>
 #include <linux/ratelimit.h>
 
-static int ptrace_scope = 1;
+#define YAMA_SCOPE_DISABLED    0
+#define YAMA_SCOPE_RELATIONAL  1
+#define YAMA_SCOPE_CAPABILITY  2
+#define YAMA_SCOPE_NO_ATTACH   3
+
+static int ptrace_scope = YAMA_SCOPE_RELATIONAL;
 
 /* describe a ptrace relationship for potential exception */
 struct ptrace_relation {
@@ -251,17 +256,32 @@ static int yama_ptrace_access_check(struct task_struct *child,
                return rc;
 
        /* require ptrace target be a child of ptracer on attach */
-       if (mode == PTRACE_MODE_ATTACH &&
-           ptrace_scope &&
-           !task_is_descendant(current, child) &&
-           !ptracer_exception_found(current, child) &&
-           !capable(CAP_SYS_PTRACE))
-               rc = -EPERM;
+       if (mode == PTRACE_MODE_ATTACH) {
+               switch (ptrace_scope) {
+               case YAMA_SCOPE_DISABLED:
+                       /* No additional restrictions. */
+                       break;
+               case YAMA_SCOPE_RELATIONAL:
+                       if (!task_is_descendant(current, child) &&
+                           !ptracer_exception_found(current, child) &&
+                           !capable(CAP_SYS_PTRACE))
+                               rc = -EPERM;
+                       break;
+               case YAMA_SCOPE_CAPABILITY:
+                       if (!capable(CAP_SYS_PTRACE))
+                               rc = -EPERM;
+                       break;
+               case YAMA_SCOPE_NO_ATTACH:
+               default:
+                       rc = -EPERM;
+                       break;
+               }
+       }
 
        if (rc) {
                char name[sizeof(current->comm)];
-               printk_ratelimited(KERN_NOTICE "ptrace of non-child"
-                       " pid %d was attempted by: %s (pid %d)\n",
+               printk_ratelimited(KERN_NOTICE
+                       "ptrace of pid %d was attempted by: %s (pid %d)\n",
                        child->pid,
                        get_task_comm(name, current),
                        current->pid);
@@ -279,8 +299,28 @@ static struct security_operations yama_ops = {
 };
 
 #ifdef CONFIG_SYSCTL
+static int yama_dointvec_minmax(struct ctl_table *table, int write,
+                               void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int rc;
+
+       if (write && !capable(CAP_SYS_PTRACE))
+               return -EPERM;
+
+       rc = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       if (rc)
+               return rc;
+
+       /* Lock the max value if it ever gets set. */
+       if (write && *(int *)table->data == *(int *)table->extra2)
+               table->extra1 = table->extra2;
+
+       return rc;
+}
+
 static int zero;
 static int one = 1;
+static int max_scope = YAMA_SCOPE_NO_ATTACH;
 
 struct ctl_path yama_sysctl_path[] = {
        { .procname = "kernel", },
@@ -294,9 +334,9 @@ static struct ctl_table yama_sysctl_table[] = {
                .data           = &ptrace_scope,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
+               .proc_handler   = yama_dointvec_minmax,
                .extra1         = &zero,
-               .extra2         = &one,
+               .extra2         = &max_scope,
        },
        { }
 };