diff options
| author | Kees Cook <keescook@chromium.org> | 2012-04-16 14:56:45 -0400 |
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2012-04-18 23:39:56 -0400 |
| commit | 389da25f93eea8ff64181ae7e3e87da68acaef2e (patch) | |
| tree | 09277860746b3372cbb49ea82868709cbae99ec3 | |
| parent | 8156b451f37898d3c3652b4e988a4d62ae16eaac (diff) | |
Yama: add additional ptrace scopes
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>
| -rw-r--r-- | Documentation/security/Yama.txt | 10 | ||||
| -rw-r--r-- | security/yama/yama_lsm.c | 62 |
2 files changed, 60 insertions, 12 deletions
diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt index a9511f179069..e369de2d48cd 100644 --- a/Documentation/security/Yama.txt +++ b/Documentation/security/Yama.txt | |||
| @@ -34,7 +34,7 @@ parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still | |||
| 34 | work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID" | 34 | work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID" |
| 35 | still work as root). | 35 | still work as root). |
| 36 | 36 | ||
| 37 | For software that has defined application-specific relationships | 37 | In mode 1, software that has defined application-specific relationships |
| 38 | between a debugging process and its inferior (crash handlers, etc), | 38 | between a debugging process and its inferior (crash handlers, etc), |
| 39 | prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which | 39 | prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which |
| 40 | other process (and its descendents) are allowed to call PTRACE_ATTACH | 40 | 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, ...) | |||
| 46 | so that any otherwise allowed process (even those in external pid namespaces) | 46 | so that any otherwise allowed process (even those in external pid namespaces) |
| 47 | may attach. | 47 | may attach. |
| 48 | 48 | ||
| 49 | These restrictions do not change how ptrace via PTRACE_TRACEME operates. | ||
| 50 | |||
| 49 | The sysctl settings are: | 51 | The sysctl settings are: |
| 50 | 52 | ||
| 51 | 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other | 53 | 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other |
| @@ -60,6 +62,12 @@ The sysctl settings are: | |||
| 60 | inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare | 62 | inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare |
| 61 | an allowed debugger PID to call PTRACE_ATTACH on the inferior. | 63 | an allowed debugger PID to call PTRACE_ATTACH on the inferior. |
| 62 | 64 | ||
| 65 | 2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace | ||
| 66 | with PTRACE_ATTACH. | ||
| 67 | |||
| 68 | 3 - no attach: no processes may use ptrace with PTRACE_ATTACH. Once set, | ||
| 69 | this sysctl cannot be changed to a lower value. | ||
| 70 | |||
| 63 | The original children-only logic was based on the restrictions in grsecurity. | 71 | The original children-only logic was based on the restrictions in grsecurity. |
| 64 | 72 | ||
| 65 | ============================================================== | 73 | ============================================================== |
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 573723843a04..afb04cbb6971 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
| @@ -18,7 +18,12 @@ | |||
| 18 | #include <linux/prctl.h> | 18 | #include <linux/prctl.h> |
| 19 | #include <linux/ratelimit.h> | 19 | #include <linux/ratelimit.h> |
| 20 | 20 | ||
| 21 | static int ptrace_scope = 1; | 21 | #define YAMA_SCOPE_DISABLED 0 |
| 22 | #define YAMA_SCOPE_RELATIONAL 1 | ||
| 23 | #define YAMA_SCOPE_CAPABILITY 2 | ||
| 24 | #define YAMA_SCOPE_NO_ATTACH 3 | ||
| 25 | |||
| 26 | static int ptrace_scope = YAMA_SCOPE_RELATIONAL; | ||
| 22 | 27 | ||
| 23 | /* describe a ptrace relationship for potential exception */ | 28 | /* describe a ptrace relationship for potential exception */ |
| 24 | struct ptrace_relation { | 29 | struct ptrace_relation { |
| @@ -251,17 +256,32 @@ static int yama_ptrace_access_check(struct task_struct *child, | |||
| 251 | return rc; | 256 | return rc; |
| 252 | 257 | ||
| 253 | /* require ptrace target be a child of ptracer on attach */ | 258 | /* require ptrace target be a child of ptracer on attach */ |
| 254 | if (mode == PTRACE_MODE_ATTACH && | 259 | if (mode == PTRACE_MODE_ATTACH) { |
| 255 | ptrace_scope && | 260 | switch (ptrace_scope) { |
| 256 | !task_is_descendant(current, child) && | 261 | case YAMA_SCOPE_DISABLED: |
| 257 | !ptracer_exception_found(current, child) && | 262 | /* No additional restrictions. */ |
| 258 | !capable(CAP_SYS_PTRACE)) | 263 | break; |
| 259 | rc = -EPERM; | 264 | case YAMA_SCOPE_RELATIONAL: |
| 265 | if (!task_is_descendant(current, child) && | ||
| 266 | !ptracer_exception_found(current, child) && | ||
| 267 | !capable(CAP_SYS_PTRACE)) | ||
| 268 | rc = -EPERM; | ||
| 269 | break; | ||
| 270 | case YAMA_SCOPE_CAPABILITY: | ||
| 271 | if (!capable(CAP_SYS_PTRACE)) | ||
| 272 | rc = -EPERM; | ||
| 273 | break; | ||
| 274 | case YAMA_SCOPE_NO_ATTACH: | ||
| 275 | default: | ||
| 276 | rc = -EPERM; | ||
| 277 | break; | ||
| 278 | } | ||
| 279 | } | ||
| 260 | 280 | ||
| 261 | if (rc) { | 281 | if (rc) { |
| 262 | char name[sizeof(current->comm)]; | 282 | char name[sizeof(current->comm)]; |
| 263 | printk_ratelimited(KERN_NOTICE "ptrace of non-child" | 283 | printk_ratelimited(KERN_NOTICE |
| 264 | " pid %d was attempted by: %s (pid %d)\n", | 284 | "ptrace of pid %d was attempted by: %s (pid %d)\n", |
| 265 | child->pid, | 285 | child->pid, |
| 266 | get_task_comm(name, current), | 286 | get_task_comm(name, current), |
| 267 | current->pid); | 287 | current->pid); |
| @@ -279,8 +299,28 @@ static struct security_operations yama_ops = { | |||
| 279 | }; | 299 | }; |
| 280 | 300 | ||
| 281 | #ifdef CONFIG_SYSCTL | 301 | #ifdef CONFIG_SYSCTL |
| 302 | static int yama_dointvec_minmax(struct ctl_table *table, int write, | ||
| 303 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 304 | { | ||
| 305 | int rc; | ||
| 306 | |||
| 307 | if (write && !capable(CAP_SYS_PTRACE)) | ||
| 308 | return -EPERM; | ||
| 309 | |||
| 310 | rc = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
| 311 | if (rc) | ||
| 312 | return rc; | ||
| 313 | |||
| 314 | /* Lock the max value if it ever gets set. */ | ||
| 315 | if (write && *(int *)table->data == *(int *)table->extra2) | ||
| 316 | table->extra1 = table->extra2; | ||
| 317 | |||
| 318 | return rc; | ||
| 319 | } | ||
| 320 | |||
| 282 | static int zero; | 321 | static int zero; |
| 283 | static int one = 1; | 322 | static int one = 1; |
| 323 | static int max_scope = YAMA_SCOPE_NO_ATTACH; | ||
| 284 | 324 | ||
| 285 | struct ctl_path yama_sysctl_path[] = { | 325 | struct ctl_path yama_sysctl_path[] = { |
| 286 | { .procname = "kernel", }, | 326 | { .procname = "kernel", }, |
| @@ -294,9 +334,9 @@ static struct ctl_table yama_sysctl_table[] = { | |||
| 294 | .data = &ptrace_scope, | 334 | .data = &ptrace_scope, |
| 295 | .maxlen = sizeof(int), | 335 | .maxlen = sizeof(int), |
| 296 | .mode = 0644, | 336 | .mode = 0644, |
| 297 | .proc_handler = proc_dointvec_minmax, | 337 | .proc_handler = yama_dointvec_minmax, |
| 298 | .extra1 = &zero, | 338 | .extra1 = &zero, |
| 299 | .extra2 = &one, | 339 | .extra2 = &max_scope, |
| 300 | }, | 340 | }, |
| 301 | { } | 341 | { } |
| 302 | }; | 342 | }; |
