Commit bf06189e4d14641c0148bea16e9dd24943862215

Authored by Kees Cook
Committed by James Morris
1 parent 3ab1aff894

Yama: add PR_SET_PTRACER_ANY

For a process to entirely disable Yama 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. This is
currently needed by the Chrome renderer, since its crash handler (Breakpad)
runs external to the renderer's pid namespace.

Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: James Morris <jmorris@namei.org>

Showing 3 changed files with 13 additions and 3 deletions Side-by-side Diff

Documentation/security/Yama.txt
... ... @@ -41,7 +41,12 @@
41 41 against it. Only one such declared debugging process can exists for
42 42 each inferior at a time. For example, this is used by KDE, Chromium, and
43 43 Firefox's crash handlers, and by Wine for allowing only Wine processes
44   -to ptrace each other.
  44 +to ptrace each other. If a process wishes to entirely disable these ptrace
  45 +restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...)
  46 +so that any otherwise allowed process (even those in external pid namespaces)
  47 +may attach.
  48 +
  49 +The sysctl settings are:
45 50  
46 51 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
47 52 process running under the same uid, as long as it is dumpable (i.e.
include/linux/prctl.h
... ... @@ -119,6 +119,7 @@
119 119 * A value of 0 mean "no process".
120 120 */
121 121 #define PR_SET_PTRACER 0x59616d61
  122 +# define PR_SET_PTRACER_ANY ((unsigned long)-1)
122 123  
123 124 #endif /* _LINUX_PRCTL_H */
security/yama/yama_lsm.c
... ... @@ -84,7 +84,7 @@
84 84 spin_lock_bh(&ptracer_relations_lock);
85 85 list_for_each_entry_safe(relation, safe, &ptracer_relations, node)
86 86 if (relation->tracee == tracee ||
87   - relation->tracer == tracer) {
  87 + (tracer && relation->tracer == tracer)) {
88 88 list_del(&relation->node);
89 89 kfree(relation);
90 90 }
... ... @@ -138,6 +138,8 @@
138 138 if (arg2 == 0) {
139 139 yama_ptracer_del(NULL, myself);
140 140 rc = 0;
  141 + } else if (arg2 == PR_SET_PTRACER_ANY) {
  142 + rc = yama_ptracer_add(NULL, myself);
141 143 } else {
142 144 struct task_struct *tracer;
143 145  
... ... @@ -208,6 +210,7 @@
208 210 int rc = 0;
209 211 struct ptrace_relation *relation;
210 212 struct task_struct *parent = NULL;
  213 + bool found = false;
211 214  
212 215 spin_lock_bh(&ptracer_relations_lock);
213 216 rcu_read_lock();
214 217  
... ... @@ -216,10 +219,11 @@
216 219 list_for_each_entry(relation, &ptracer_relations, node)
217 220 if (relation->tracee == tracee) {
218 221 parent = relation->tracer;
  222 + found = true;
219 223 break;
220 224 }
221 225  
222   - if (task_is_descendant(parent, tracer))
  226 + if (found && (parent == NULL || task_is_descendant(parent, tracer)))
223 227 rc = 1;
224 228 rcu_read_unlock();
225 229 spin_unlock_bh(&ptracer_relations_lock);