Skip to content

Commit

Permalink
Yama: add additional ptrace scopes
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: James Morris <[email protected]>
  • Loading branch information
kees authored and James Morris committed Apr 19, 2012
1 parent 8156b45 commit 389da25
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 12 deletions.
10 changes: 9 additions & 1 deletion Documentation/security/Yama.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.

==============================================================
62 changes: 51 additions & 11 deletions security/yama/yama_lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@
#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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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", },
Expand All @@ -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,
},
{ }
};
Expand Down

0 comments on commit 389da25

Please sign in to comment.