UBUNTU: SAUCE: (drop after 3.3) Yama: add PR_SET_PTRACER_ANY
authorKees Cook <keescook@chromium.org>
Fri, 20 Jan 2012 01:58:35 +0000 (17:58 -0800)
committerLeann Ogasawara <leann.ogasawara@canonical.com>
Mon, 2 Apr 2012 20:21:21 +0000 (13:21 -0700)
For a process to entirely disable ptrace restrictions, it can use the
special PR_SET_PTRACER_ANY pid to indicate that any otherwise allowed
process may ptrace it. This is stronger than calling PR_SET_PTRACER with
pid "1" because it includes processes in external pid namespaces.

Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>

Documentation/security/Yama.txt
include/linux/prctl.h
security/yama/yama_lsm.c

index 4f0b789..dcb4695 100644 (file)
@@ -41,7 +41,11 @@ other process (and its descendents) are allowed to call PTRACE_ATTACH
 against it. Only one such declared debugging process can exists for
 each inferior at a time. For example, this is used by KDE, Chromium, and
 Firefox's crash handlers, and by Wine for allowing only Wine processes
-to ptrace each other.
+to ptrace each other. If a process wishes to entirely disable ptrace
+restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...)
+so that any process (even those in external pid namespaces) may attach.
+
+The sysctl settings are:
 
 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
     process running under the same uid, as long as it is dumpable (i.e.
index 4d0e5bc..a0413ac 100644 (file)
  * A value of 0 mean "no process".
  */
 #define PR_SET_PTRACER 0x59616d61
+# define PR_SET_PTRACER_ANY ((unsigned long)-1)
 
 #endif /* _LINUX_PRCTL_H */
index dd4d360..d8f892c 100644 (file)
@@ -84,7 +84,7 @@ static void yama_ptracer_del(struct task_struct *tracer,
        spin_lock_bh(&ptracer_relations_lock);
        list_for_each_entry_safe(relation, safe, &ptracer_relations, node)
                if (relation->tracee == tracee ||
-                   relation->tracer == tracer) {
+                   (tracer && relation->tracer == tracer)) {
                        list_del(&relation->node);
                        kfree(relation);
                }
@@ -138,6 +138,9 @@ static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                if (arg2 == 0) {
                        yama_ptracer_del(NULL, myself);
                        rc = 0;
+               }
+               else if (arg2 == PR_SET_PTRACER_ANY) {
+                       rc = yama_ptracer_add(NULL, myself);
                } else {
                        struct task_struct *tracer;
 
@@ -208,6 +211,7 @@ static int ptracer_exception_found(struct task_struct *tracer,
        int rc = 0;
        struct ptrace_relation *relation;
        struct task_struct *parent = NULL;
+       bool found = false;
 
        spin_lock_bh(&ptracer_relations_lock);
        rcu_read_lock();
@@ -216,10 +220,11 @@ static int ptracer_exception_found(struct task_struct *tracer,
        list_for_each_entry(relation, &ptracer_relations, node)
                if (relation->tracee == tracee) {
                        parent = relation->tracer;
+                       found = true;
                        break;
                }
 
-       if (task_is_descendant(parent, tracer))
+       if (found && (parent == NULL || task_is_descendant(parent, tracer)))
                rc = 1;
        rcu_read_unlock();
        spin_unlock_bh(&ptracer_relations_lock);