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>
diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt
index a9511f1..e369de2 100644
--- a/Documentation/security/Yama.txt
+++ b/Documentation/security/Yama.txt
@@ -34,7 +34,7 @@
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
@@ -46,6 +46,8 @@
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
@@ -60,6 +62,12 @@
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.
==============================================================
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 5737238..afb04cb 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -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 {
@@ -251,17 +256,32 @@
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);
@@ -279,8 +299,28 @@
};
#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", },
@@ -294,9 +334,9 @@
.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,
},
{ }
};