forked from mirrors/linux
		
	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>
This commit is contained in:
		
							parent
							
								
									8156b451f3
								
							
						
					
					
						commit
						389da25f93
					
				
					 2 changed files with 60 additions and 12 deletions
				
			
		| 
						 | 
					@ -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"
 | 
					work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID"
 | 
				
			||||||
still work as root).
 | 
					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),
 | 
					between a debugging process and its inferior (crash handlers, etc),
 | 
				
			||||||
prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which
 | 
					prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which
 | 
				
			||||||
other process (and its descendents) are allowed to call PTRACE_ATTACH
 | 
					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, ...)
 | 
				
			||||||
so that any otherwise allowed process (even those in external pid namespaces)
 | 
					so that any otherwise allowed process (even those in external pid namespaces)
 | 
				
			||||||
may attach.
 | 
					may attach.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These restrictions do not change how ptrace via PTRACE_TRACEME operates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The sysctl settings are:
 | 
					The sysctl settings are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
 | 
					0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
 | 
				
			||||||
| 
						 | 
					@ -60,6 +62,12 @@ The sysctl settings are:
 | 
				
			||||||
    inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare
 | 
					    inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare
 | 
				
			||||||
    an allowed debugger PID to call PTRACE_ATTACH on the inferior.
 | 
					    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.
 | 
					The original children-only logic was based on the restrictions in grsecurity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
==============================================================
 | 
					==============================================================
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,12 @@
 | 
				
			||||||
#include <linux/prctl.h>
 | 
					#include <linux/prctl.h>
 | 
				
			||||||
#include <linux/ratelimit.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 */
 | 
					/* describe a ptrace relationship for potential exception */
 | 
				
			||||||
struct ptrace_relation {
 | 
					struct ptrace_relation {
 | 
				
			||||||
| 
						 | 
					@ -251,17 +256,32 @@ static int yama_ptrace_access_check(struct task_struct *child,
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* require ptrace target be a child of ptracer on attach */
 | 
						/* require ptrace target be a child of ptracer on attach */
 | 
				
			||||||
	if (mode == PTRACE_MODE_ATTACH &&
 | 
						if (mode == PTRACE_MODE_ATTACH) {
 | 
				
			||||||
	    ptrace_scope &&
 | 
							switch (ptrace_scope) {
 | 
				
			||||||
	    !task_is_descendant(current, child) &&
 | 
							case YAMA_SCOPE_DISABLED:
 | 
				
			||||||
	    !ptracer_exception_found(current, child) &&
 | 
								/* No additional restrictions. */
 | 
				
			||||||
	    !capable(CAP_SYS_PTRACE))
 | 
								break;
 | 
				
			||||||
		rc = -EPERM;
 | 
							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) {
 | 
						if (rc) {
 | 
				
			||||||
		char name[sizeof(current->comm)];
 | 
							char name[sizeof(current->comm)];
 | 
				
			||||||
		printk_ratelimited(KERN_NOTICE "ptrace of non-child"
 | 
							printk_ratelimited(KERN_NOTICE
 | 
				
			||||||
			" pid %d was attempted by: %s (pid %d)\n",
 | 
								"ptrace of pid %d was attempted by: %s (pid %d)\n",
 | 
				
			||||||
			child->pid,
 | 
								child->pid,
 | 
				
			||||||
			get_task_comm(name, current),
 | 
								get_task_comm(name, current),
 | 
				
			||||||
			current->pid);
 | 
								current->pid);
 | 
				
			||||||
| 
						 | 
					@ -279,8 +299,28 @@ static struct security_operations yama_ops = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SYSCTL
 | 
					#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 zero;
 | 
				
			||||||
static int one = 1;
 | 
					static int one = 1;
 | 
				
			||||||
 | 
					static int max_scope = YAMA_SCOPE_NO_ATTACH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ctl_path yama_sysctl_path[] = {
 | 
					struct ctl_path yama_sysctl_path[] = {
 | 
				
			||||||
	{ .procname = "kernel", },
 | 
						{ .procname = "kernel", },
 | 
				
			||||||
| 
						 | 
					@ -294,9 +334,9 @@ static struct ctl_table yama_sysctl_table[] = {
 | 
				
			||||||
		.data           = &ptrace_scope,
 | 
							.data           = &ptrace_scope,
 | 
				
			||||||
		.maxlen         = sizeof(int),
 | 
							.maxlen         = sizeof(int),
 | 
				
			||||||
		.mode           = 0644,
 | 
							.mode           = 0644,
 | 
				
			||||||
		.proc_handler   = proc_dointvec_minmax,
 | 
							.proc_handler   = yama_dointvec_minmax,
 | 
				
			||||||
		.extra1         = &zero,
 | 
							.extra1         = &zero,
 | 
				
			||||||
		.extra2         = &one,
 | 
							.extra2         = &max_scope,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{ }
 | 
						{ }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue