xref: /openbmc/linux/security/yama/yama_lsm.c (revision 2d514487faf188938a4ee4fb3464eeecfbdcf8eb)
1*2d514487SKees Cook /*
2*2d514487SKees Cook  * Yama Linux Security Module
3*2d514487SKees Cook  *
4*2d514487SKees Cook  * Author: Kees Cook <keescook@chromium.org>
5*2d514487SKees Cook  *
6*2d514487SKees Cook  * Copyright (C) 2010 Canonical, Ltd.
7*2d514487SKees Cook  * Copyright (C) 2011 The Chromium OS Authors.
8*2d514487SKees Cook  *
9*2d514487SKees Cook  * This program is free software; you can redistribute it and/or modify
10*2d514487SKees Cook  * it under the terms of the GNU General Public License version 2, as
11*2d514487SKees Cook  * published by the Free Software Foundation.
12*2d514487SKees Cook  *
13*2d514487SKees Cook  */
14*2d514487SKees Cook 
15*2d514487SKees Cook #include <linux/security.h>
16*2d514487SKees Cook #include <linux/sysctl.h>
17*2d514487SKees Cook #include <linux/ptrace.h>
18*2d514487SKees Cook #include <linux/prctl.h>
19*2d514487SKees Cook #include <linux/ratelimit.h>
20*2d514487SKees Cook 
21*2d514487SKees Cook static int ptrace_scope = 1;
22*2d514487SKees Cook 
23*2d514487SKees Cook /* describe a ptrace relationship for potential exception */
24*2d514487SKees Cook struct ptrace_relation {
25*2d514487SKees Cook 	struct task_struct *tracer;
26*2d514487SKees Cook 	struct task_struct *tracee;
27*2d514487SKees Cook 	struct list_head node;
28*2d514487SKees Cook };
29*2d514487SKees Cook 
30*2d514487SKees Cook static LIST_HEAD(ptracer_relations);
31*2d514487SKees Cook static DEFINE_SPINLOCK(ptracer_relations_lock);
32*2d514487SKees Cook 
33*2d514487SKees Cook /**
34*2d514487SKees Cook  * yama_ptracer_add - add/replace an exception for this tracer/tracee pair
35*2d514487SKees Cook  * @tracer: the task_struct of the process doing the ptrace
36*2d514487SKees Cook  * @tracee: the task_struct of the process to be ptraced
37*2d514487SKees Cook  *
38*2d514487SKees Cook  * Each tracee can have, at most, one tracer registered. Each time this
39*2d514487SKees Cook  * is called, the prior registered tracer will be replaced for the tracee.
40*2d514487SKees Cook  *
41*2d514487SKees Cook  * Returns 0 if relationship was added, -ve on error.
42*2d514487SKees Cook  */
43*2d514487SKees Cook static int yama_ptracer_add(struct task_struct *tracer,
44*2d514487SKees Cook 			    struct task_struct *tracee)
45*2d514487SKees Cook {
46*2d514487SKees Cook 	int rc = 0;
47*2d514487SKees Cook 	struct ptrace_relation *added;
48*2d514487SKees Cook 	struct ptrace_relation *entry, *relation = NULL;
49*2d514487SKees Cook 
50*2d514487SKees Cook 	added = kmalloc(sizeof(*added), GFP_KERNEL);
51*2d514487SKees Cook 	if (!added)
52*2d514487SKees Cook 		return -ENOMEM;
53*2d514487SKees Cook 
54*2d514487SKees Cook 	spin_lock_bh(&ptracer_relations_lock);
55*2d514487SKees Cook 	list_for_each_entry(entry, &ptracer_relations, node)
56*2d514487SKees Cook 		if (entry->tracee == tracee) {
57*2d514487SKees Cook 			relation = entry;
58*2d514487SKees Cook 			break;
59*2d514487SKees Cook 		}
60*2d514487SKees Cook 	if (!relation) {
61*2d514487SKees Cook 		relation = added;
62*2d514487SKees Cook 		relation->tracee = tracee;
63*2d514487SKees Cook 		list_add(&relation->node, &ptracer_relations);
64*2d514487SKees Cook 	}
65*2d514487SKees Cook 	relation->tracer = tracer;
66*2d514487SKees Cook 
67*2d514487SKees Cook 	spin_unlock_bh(&ptracer_relations_lock);
68*2d514487SKees Cook 	if (added != relation)
69*2d514487SKees Cook 		kfree(added);
70*2d514487SKees Cook 
71*2d514487SKees Cook 	return rc;
72*2d514487SKees Cook }
73*2d514487SKees Cook 
74*2d514487SKees Cook /**
75*2d514487SKees Cook  * yama_ptracer_del - remove exceptions related to the given tasks
76*2d514487SKees Cook  * @tracer: remove any relation where tracer task matches
77*2d514487SKees Cook  * @tracee: remove any relation where tracee task matches
78*2d514487SKees Cook  */
79*2d514487SKees Cook static void yama_ptracer_del(struct task_struct *tracer,
80*2d514487SKees Cook 			     struct task_struct *tracee)
81*2d514487SKees Cook {
82*2d514487SKees Cook 	struct ptrace_relation *relation, *safe;
83*2d514487SKees Cook 
84*2d514487SKees Cook 	spin_lock_bh(&ptracer_relations_lock);
85*2d514487SKees Cook 	list_for_each_entry_safe(relation, safe, &ptracer_relations, node)
86*2d514487SKees Cook 		if (relation->tracee == tracee ||
87*2d514487SKees Cook 		    relation->tracer == tracer) {
88*2d514487SKees Cook 			list_del(&relation->node);
89*2d514487SKees Cook 			kfree(relation);
90*2d514487SKees Cook 		}
91*2d514487SKees Cook 	spin_unlock_bh(&ptracer_relations_lock);
92*2d514487SKees Cook }
93*2d514487SKees Cook 
94*2d514487SKees Cook /**
95*2d514487SKees Cook  * yama_task_free - check for task_pid to remove from exception list
96*2d514487SKees Cook  * @task: task being removed
97*2d514487SKees Cook  */
98*2d514487SKees Cook static void yama_task_free(struct task_struct *task)
99*2d514487SKees Cook {
100*2d514487SKees Cook 	yama_ptracer_del(task, task);
101*2d514487SKees Cook }
102*2d514487SKees Cook 
103*2d514487SKees Cook /**
104*2d514487SKees Cook  * yama_task_prctl - check for Yama-specific prctl operations
105*2d514487SKees Cook  * @option: operation
106*2d514487SKees Cook  * @arg2: argument
107*2d514487SKees Cook  * @arg3: argument
108*2d514487SKees Cook  * @arg4: argument
109*2d514487SKees Cook  * @arg5: argument
110*2d514487SKees Cook  *
111*2d514487SKees Cook  * Return 0 on success, -ve on error.  -ENOSYS is returned when Yama
112*2d514487SKees Cook  * does not handle the given option.
113*2d514487SKees Cook  */
114*2d514487SKees Cook static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
115*2d514487SKees Cook 			   unsigned long arg4, unsigned long arg5)
116*2d514487SKees Cook {
117*2d514487SKees Cook 	int rc;
118*2d514487SKees Cook 	struct task_struct *myself = current;
119*2d514487SKees Cook 
120*2d514487SKees Cook 	rc = cap_task_prctl(option, arg2, arg3, arg4, arg5);
121*2d514487SKees Cook 	if (rc != -ENOSYS)
122*2d514487SKees Cook 		return rc;
123*2d514487SKees Cook 
124*2d514487SKees Cook 	switch (option) {
125*2d514487SKees Cook 	case PR_SET_PTRACER:
126*2d514487SKees Cook 		/* Since a thread can call prctl(), find the group leader
127*2d514487SKees Cook 		 * before calling _add() or _del() on it, since we want
128*2d514487SKees Cook 		 * process-level granularity of control. The tracer group
129*2d514487SKees Cook 		 * leader checking is handled later when walking the ancestry
130*2d514487SKees Cook 		 * at the time of PTRACE_ATTACH check.
131*2d514487SKees Cook 		 */
132*2d514487SKees Cook 		rcu_read_lock();
133*2d514487SKees Cook 		if (!thread_group_leader(myself))
134*2d514487SKees Cook 			myself = rcu_dereference(myself->group_leader);
135*2d514487SKees Cook 		get_task_struct(myself);
136*2d514487SKees Cook 		rcu_read_unlock();
137*2d514487SKees Cook 
138*2d514487SKees Cook 		if (arg2 == 0) {
139*2d514487SKees Cook 			yama_ptracer_del(NULL, myself);
140*2d514487SKees Cook 			rc = 0;
141*2d514487SKees Cook 		} else {
142*2d514487SKees Cook 			struct task_struct *tracer;
143*2d514487SKees Cook 
144*2d514487SKees Cook 			rcu_read_lock();
145*2d514487SKees Cook 			tracer = find_task_by_vpid(arg2);
146*2d514487SKees Cook 			if (tracer)
147*2d514487SKees Cook 				get_task_struct(tracer);
148*2d514487SKees Cook 			else
149*2d514487SKees Cook 				rc = -EINVAL;
150*2d514487SKees Cook 			rcu_read_unlock();
151*2d514487SKees Cook 
152*2d514487SKees Cook 			if (tracer) {
153*2d514487SKees Cook 				rc = yama_ptracer_add(tracer, myself);
154*2d514487SKees Cook 				put_task_struct(tracer);
155*2d514487SKees Cook 			}
156*2d514487SKees Cook 		}
157*2d514487SKees Cook 
158*2d514487SKees Cook 		put_task_struct(myself);
159*2d514487SKees Cook 		break;
160*2d514487SKees Cook 	}
161*2d514487SKees Cook 
162*2d514487SKees Cook 	return rc;
163*2d514487SKees Cook }
164*2d514487SKees Cook 
165*2d514487SKees Cook /**
166*2d514487SKees Cook  * task_is_descendant - walk up a process family tree looking for a match
167*2d514487SKees Cook  * @parent: the process to compare against while walking up from child
168*2d514487SKees Cook  * @child: the process to start from while looking upwards for parent
169*2d514487SKees Cook  *
170*2d514487SKees Cook  * Returns 1 if child is a descendant of parent, 0 if not.
171*2d514487SKees Cook  */
172*2d514487SKees Cook static int task_is_descendant(struct task_struct *parent,
173*2d514487SKees Cook 			      struct task_struct *child)
174*2d514487SKees Cook {
175*2d514487SKees Cook 	int rc = 0;
176*2d514487SKees Cook 	struct task_struct *walker = child;
177*2d514487SKees Cook 
178*2d514487SKees Cook 	if (!parent || !child)
179*2d514487SKees Cook 		return 0;
180*2d514487SKees Cook 
181*2d514487SKees Cook 	rcu_read_lock();
182*2d514487SKees Cook 	if (!thread_group_leader(parent))
183*2d514487SKees Cook 		parent = rcu_dereference(parent->group_leader);
184*2d514487SKees Cook 	while (walker->pid > 0) {
185*2d514487SKees Cook 		if (!thread_group_leader(walker))
186*2d514487SKees Cook 			walker = rcu_dereference(walker->group_leader);
187*2d514487SKees Cook 		if (walker == parent) {
188*2d514487SKees Cook 			rc = 1;
189*2d514487SKees Cook 			break;
190*2d514487SKees Cook 		}
191*2d514487SKees Cook 		walker = rcu_dereference(walker->real_parent);
192*2d514487SKees Cook 	}
193*2d514487SKees Cook 	rcu_read_unlock();
194*2d514487SKees Cook 
195*2d514487SKees Cook 	return rc;
196*2d514487SKees Cook }
197*2d514487SKees Cook 
198*2d514487SKees Cook /**
199*2d514487SKees Cook  * ptracer_exception_found - tracer registered as exception for this tracee
200*2d514487SKees Cook  * @tracer: the task_struct of the process attempting ptrace
201*2d514487SKees Cook  * @tracee: the task_struct of the process to be ptraced
202*2d514487SKees Cook  *
203*2d514487SKees Cook  * Returns 1 if tracer has is ptracer exception ancestor for tracee.
204*2d514487SKees Cook  */
205*2d514487SKees Cook static int ptracer_exception_found(struct task_struct *tracer,
206*2d514487SKees Cook 				   struct task_struct *tracee)
207*2d514487SKees Cook {
208*2d514487SKees Cook 	int rc = 0;
209*2d514487SKees Cook 	struct ptrace_relation *relation;
210*2d514487SKees Cook 	struct task_struct *parent = NULL;
211*2d514487SKees Cook 
212*2d514487SKees Cook 	spin_lock_bh(&ptracer_relations_lock);
213*2d514487SKees Cook 	rcu_read_lock();
214*2d514487SKees Cook 	if (!thread_group_leader(tracee))
215*2d514487SKees Cook 		tracee = rcu_dereference(tracee->group_leader);
216*2d514487SKees Cook 	list_for_each_entry(relation, &ptracer_relations, node)
217*2d514487SKees Cook 		if (relation->tracee == tracee) {
218*2d514487SKees Cook 			parent = relation->tracer;
219*2d514487SKees Cook 			break;
220*2d514487SKees Cook 		}
221*2d514487SKees Cook 
222*2d514487SKees Cook 	if (task_is_descendant(parent, tracer))
223*2d514487SKees Cook 		rc = 1;
224*2d514487SKees Cook 	rcu_read_unlock();
225*2d514487SKees Cook 	spin_unlock_bh(&ptracer_relations_lock);
226*2d514487SKees Cook 
227*2d514487SKees Cook 	return rc;
228*2d514487SKees Cook }
229*2d514487SKees Cook 
230*2d514487SKees Cook /**
231*2d514487SKees Cook  * yama_ptrace_access_check - validate PTRACE_ATTACH calls
232*2d514487SKees Cook  * @child: task that current task is attempting to ptrace
233*2d514487SKees Cook  * @mode: ptrace attach mode
234*2d514487SKees Cook  *
235*2d514487SKees Cook  * Returns 0 if following the ptrace is allowed, -ve on error.
236*2d514487SKees Cook  */
237*2d514487SKees Cook static int yama_ptrace_access_check(struct task_struct *child,
238*2d514487SKees Cook 				    unsigned int mode)
239*2d514487SKees Cook {
240*2d514487SKees Cook 	int rc;
241*2d514487SKees Cook 
242*2d514487SKees Cook 	/* If standard caps disallows it, so does Yama.  We should
243*2d514487SKees Cook 	 * only tighten restrictions further.
244*2d514487SKees Cook 	 */
245*2d514487SKees Cook 	rc = cap_ptrace_access_check(child, mode);
246*2d514487SKees Cook 	if (rc)
247*2d514487SKees Cook 		return rc;
248*2d514487SKees Cook 
249*2d514487SKees Cook 	/* require ptrace target be a child of ptracer on attach */
250*2d514487SKees Cook 	if (mode == PTRACE_MODE_ATTACH &&
251*2d514487SKees Cook 	    ptrace_scope &&
252*2d514487SKees Cook 	    !task_is_descendant(current, child) &&
253*2d514487SKees Cook 	    !ptracer_exception_found(current, child) &&
254*2d514487SKees Cook 	    !capable(CAP_SYS_PTRACE))
255*2d514487SKees Cook 		rc = -EPERM;
256*2d514487SKees Cook 
257*2d514487SKees Cook 	if (rc) {
258*2d514487SKees Cook 		char name[sizeof(current->comm)];
259*2d514487SKees Cook 		printk_ratelimited(KERN_NOTICE "ptrace of non-child"
260*2d514487SKees Cook 			" pid %d was attempted by: %s (pid %d)\n",
261*2d514487SKees Cook 			child->pid,
262*2d514487SKees Cook 			get_task_comm(name, current),
263*2d514487SKees Cook 			current->pid);
264*2d514487SKees Cook 	}
265*2d514487SKees Cook 
266*2d514487SKees Cook 	return rc;
267*2d514487SKees Cook }
268*2d514487SKees Cook 
269*2d514487SKees Cook static struct security_operations yama_ops = {
270*2d514487SKees Cook 	.name =			"yama",
271*2d514487SKees Cook 
272*2d514487SKees Cook 	.ptrace_access_check =	yama_ptrace_access_check,
273*2d514487SKees Cook 	.task_prctl =		yama_task_prctl,
274*2d514487SKees Cook 	.task_free =		yama_task_free,
275*2d514487SKees Cook };
276*2d514487SKees Cook 
277*2d514487SKees Cook #ifdef CONFIG_SYSCTL
278*2d514487SKees Cook static int zero;
279*2d514487SKees Cook static int one = 1;
280*2d514487SKees Cook 
281*2d514487SKees Cook struct ctl_path yama_sysctl_path[] = {
282*2d514487SKees Cook 	{ .procname = "kernel", },
283*2d514487SKees Cook 	{ .procname = "yama", },
284*2d514487SKees Cook 	{ }
285*2d514487SKees Cook };
286*2d514487SKees Cook 
287*2d514487SKees Cook static struct ctl_table yama_sysctl_table[] = {
288*2d514487SKees Cook 	{
289*2d514487SKees Cook 		.procname       = "ptrace_scope",
290*2d514487SKees Cook 		.data           = &ptrace_scope,
291*2d514487SKees Cook 		.maxlen         = sizeof(int),
292*2d514487SKees Cook 		.mode           = 0644,
293*2d514487SKees Cook 		.proc_handler   = proc_dointvec_minmax,
294*2d514487SKees Cook 		.extra1         = &zero,
295*2d514487SKees Cook 		.extra2         = &one,
296*2d514487SKees Cook 	},
297*2d514487SKees Cook 	{ }
298*2d514487SKees Cook };
299*2d514487SKees Cook #endif /* CONFIG_SYSCTL */
300*2d514487SKees Cook 
301*2d514487SKees Cook static __init int yama_init(void)
302*2d514487SKees Cook {
303*2d514487SKees Cook 	if (!security_module_enable(&yama_ops))
304*2d514487SKees Cook 		return 0;
305*2d514487SKees Cook 
306*2d514487SKees Cook 	printk(KERN_INFO "Yama: becoming mindful.\n");
307*2d514487SKees Cook 
308*2d514487SKees Cook 	if (register_security(&yama_ops))
309*2d514487SKees Cook 		panic("Yama: kernel registration failed.\n");
310*2d514487SKees Cook 
311*2d514487SKees Cook #ifdef CONFIG_SYSCTL
312*2d514487SKees Cook 	if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))
313*2d514487SKees Cook 		panic("Yama: sysctl registration failed.\n");
314*2d514487SKees Cook #endif
315*2d514487SKees Cook 
316*2d514487SKees Cook 	return 0;
317*2d514487SKees Cook }
318*2d514487SKees Cook 
319*2d514487SKees Cook security_initcall(yama_init);
320