diff options
-rw-r--r-- | Documentation/security/Yama.txt | 7 | ||||
-rw-r--r-- | include/linux/prctl.h | 1 | ||||
-rw-r--r-- | security/yama/yama_lsm.c | 8 |
3 files changed, 13 insertions, 3 deletions
diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt index 4f0b7896a21d..a9511f179069 100644 --- a/Documentation/security/Yama.txt +++ b/Documentation/security/Yama.txt | |||
@@ -41,7 +41,12 @@ other process (and its descendents) are allowed to call PTRACE_ATTACH | |||
41 | against it. Only one such declared debugging process can exists for | 41 | against it. Only one such declared debugging process can exists for |
42 | each inferior at a time. For example, this is used by KDE, Chromium, and | 42 | each inferior at a time. For example, this is used by KDE, Chromium, and |
43 | Firefox's crash handlers, and by Wine for allowing only Wine processes | 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 | 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other | 51 | 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other |
47 | process running under the same uid, as long as it is dumpable (i.e. | 52 | process running under the same uid, as long as it is dumpable (i.e. |
diff --git a/include/linux/prctl.h b/include/linux/prctl.h index 4d0e5bc5458c..a0413ac3abe8 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h | |||
@@ -119,5 +119,6 @@ | |||
119 | * A value of 0 mean "no process". | 119 | * A value of 0 mean "no process". |
120 | */ | 120 | */ |
121 | #define PR_SET_PTRACER 0x59616d61 | 121 | #define PR_SET_PTRACER 0x59616d61 |
122 | # define PR_SET_PTRACER_ANY ((unsigned long)-1) | ||
122 | 123 | ||
123 | #endif /* _LINUX_PRCTL_H */ | 124 | #endif /* _LINUX_PRCTL_H */ |
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index dd4d36067c50..573723843a04 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
@@ -84,7 +84,7 @@ static void yama_ptracer_del(struct task_struct *tracer, | |||
84 | spin_lock_bh(&ptracer_relations_lock); | 84 | spin_lock_bh(&ptracer_relations_lock); |
85 | list_for_each_entry_safe(relation, safe, &ptracer_relations, node) | 85 | list_for_each_entry_safe(relation, safe, &ptracer_relations, node) |
86 | if (relation->tracee == tracee || | 86 | if (relation->tracee == tracee || |
87 | relation->tracer == tracer) { | 87 | (tracer && relation->tracer == tracer)) { |
88 | list_del(&relation->node); | 88 | list_del(&relation->node); |
89 | kfree(relation); | 89 | kfree(relation); |
90 | } | 90 | } |
@@ -138,6 +138,8 @@ static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
138 | if (arg2 == 0) { | 138 | if (arg2 == 0) { |
139 | yama_ptracer_del(NULL, myself); | 139 | yama_ptracer_del(NULL, myself); |
140 | rc = 0; | 140 | rc = 0; |
141 | } else if (arg2 == PR_SET_PTRACER_ANY) { | ||
142 | rc = yama_ptracer_add(NULL, myself); | ||
141 | } else { | 143 | } else { |
142 | struct task_struct *tracer; | 144 | struct task_struct *tracer; |
143 | 145 | ||
@@ -208,6 +210,7 @@ static int ptracer_exception_found(struct task_struct *tracer, | |||
208 | int rc = 0; | 210 | int rc = 0; |
209 | struct ptrace_relation *relation; | 211 | struct ptrace_relation *relation; |
210 | struct task_struct *parent = NULL; | 212 | struct task_struct *parent = NULL; |
213 | bool found = false; | ||
211 | 214 | ||
212 | spin_lock_bh(&ptracer_relations_lock); | 215 | spin_lock_bh(&ptracer_relations_lock); |
213 | rcu_read_lock(); | 216 | rcu_read_lock(); |
@@ -216,10 +219,11 @@ static int ptracer_exception_found(struct task_struct *tracer, | |||
216 | list_for_each_entry(relation, &ptracer_relations, node) | 219 | list_for_each_entry(relation, &ptracer_relations, node) |
217 | if (relation->tracee == tracee) { | 220 | if (relation->tracee == tracee) { |
218 | parent = relation->tracer; | 221 | parent = relation->tracer; |
222 | found = true; | ||
219 | break; | 223 | break; |
220 | } | 224 | } |
221 | 225 | ||
222 | if (task_is_descendant(parent, tracer)) | 226 | if (found && (parent == NULL || task_is_descendant(parent, tracer))) |
223 | rc = 1; | 227 | rc = 1; |
224 | rcu_read_unlock(); | 228 | rcu_read_unlock(); |
225 | spin_unlock_bh(&ptracer_relations_lock); | 229 | spin_unlock_bh(&ptracer_relations_lock); |