1100894Srwatson/*-
2189503Srwatson * Copyright (c) 1999-2002, 2008-2009 Robert N. M. Watson
3100894Srwatson * Copyright (c) 2001 Ilmar S. Habibulin
4126097Srwatson * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
5172930Srwatson * Copyright (c) 2006 SPARTA, Inc.
6182063Srwatson * Copyright (c) 2008 Apple Inc.
7100894Srwatson * All rights reserved.
8100894Srwatson *
9100894Srwatson * This software was developed by Robert Watson and Ilmar Habibulin for the
10100894Srwatson * TrustedBSD Project.
11100894Srwatson *
12106392Srwatson * This software was developed for the FreeBSD Project in part by Network
13106392Srwatson * Associates Laboratories, the Security Research Division of Network
14106392Srwatson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15106392Srwatson * as part of the DARPA CHATS research program.
16100894Srwatson *
17172930Srwatson * This software was enhanced by SPARTA ISSO under SPAWAR contract
18172930Srwatson * N66001-04-C-6019 ("SEFOS").
19172930Srwatson *
20189503Srwatson * This software was developed at the University of Cambridge Computer
21189503Srwatson * Laboratory with support from a grant from Google, Inc.
22189503Srwatson *
23100894Srwatson * Redistribution and use in source and binary forms, with or without
24100894Srwatson * modification, are permitted provided that the following conditions
25100894Srwatson * are met:
26100894Srwatson * 1. Redistributions of source code must retain the above copyright
27100894Srwatson *    notice, this list of conditions and the following disclaimer.
28100894Srwatson * 2. Redistributions in binary form must reproduce the above copyright
29100894Srwatson *    notice, this list of conditions and the following disclaimer in the
30100894Srwatson *    documentation and/or other materials provided with the distribution.
31100894Srwatson *
32100894Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33100894Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34100894Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35100894Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36100894Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37100894Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38100894Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39100894Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40100894Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41100894Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42100894Srwatson * SUCH DAMAGE.
43100894Srwatson */
44116182Sobrien
45116182Sobrien#include <sys/cdefs.h>
46116182Sobrien__FBSDID("$FreeBSD$");
47116182Sobrien
48189503Srwatson#include "opt_kdtrace.h"
49100894Srwatson#include "opt_mac.h"
50101173Srwatson
51100894Srwatson#include <sys/param.h>
52106856Srwatson#include <sys/condvar.h>
53106468Srwatson#include <sys/imgact.h>
54100979Srwatson#include <sys/kernel.h>
55100979Srwatson#include <sys/lock.h>
56102949Sbde#include <sys/malloc.h>
57100979Srwatson#include <sys/mutex.h>
58100979Srwatson#include <sys/mac.h>
59100979Srwatson#include <sys/proc.h>
60116701Srwatson#include <sys/sbuf.h>
61189503Srwatson#include <sys/sdt.h>
62100979Srwatson#include <sys/systm.h>
63100979Srwatson#include <sys/vnode.h>
64100979Srwatson#include <sys/mount.h>
65100979Srwatson#include <sys/file.h>
66100979Srwatson#include <sys/namei.h>
67100979Srwatson#include <sys/sysctl.h>
68100894Srwatson
69100979Srwatson#include <vm/vm.h>
70100979Srwatson#include <vm/pmap.h>
71100979Srwatson#include <vm/vm_map.h>
72100979Srwatson#include <vm/vm_object.h>
73100979Srwatson
74163606Srwatson#include <security/mac/mac_framework.h>
75121361Srwatson#include <security/mac/mac_internal.h>
76165469Srwatson#include <security/mac/mac_policy.h>
77100979Srwatson
78103136Srwatsonstatic int	mac_mmap_revocation = 1;
79103136SrwatsonSYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW,
80103136Srwatson    &mac_mmap_revocation, 0, "Revoke mmap access to files on subject "
81103136Srwatson    "relabel");
82121361Srwatson
83101892Srwatsonstatic int	mac_mmap_revocation_via_cow = 0;
84100979SrwatsonSYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW,
85100979Srwatson    &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via "
86100979Srwatson    "copy-on-write semantics, or by removing all write access");
87100979Srwatson
88184412Srwatsonstatic void	mac_proc_vm_revoke_recurse(struct thread *td,
89100979Srwatson		    struct ucred *cred, struct vm_map *map);
90100979Srwatson
91122524Srwatsonstatic struct label *
92122524Srwatsonmac_proc_label_alloc(void)
93122524Srwatson{
94122524Srwatson	struct label *label;
95122524Srwatson
96122524Srwatson	label = mac_labelzone_alloc(M_WAITOK);
97191731Srwatson	MAC_POLICY_PERFORM(proc_init_label, label);
98122524Srwatson	return (label);
99122524Srwatson}
100122524Srwatson
101105694Srwatsonvoid
102172930Srwatsonmac_proc_init(struct proc *p)
103107105Srwatson{
104107105Srwatson
105182063Srwatson	if (mac_labeled & MPC_OBJECT_PROC)
106182063Srwatson		p->p_label = mac_proc_label_alloc();
107182063Srwatson	else
108182063Srwatson		p->p_label = NULL;
109107105Srwatson}
110107105Srwatson
111122524Srwatsonstatic void
112122524Srwatsonmac_proc_label_free(struct label *label)
113122524Srwatson{
114122524Srwatson
115191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(proc_destroy_label, label);
116122524Srwatson	mac_labelzone_free(label);
117122524Srwatson}
118122524Srwatson
119105694Srwatsonvoid
120172930Srwatsonmac_proc_destroy(struct proc *p)
121107105Srwatson{
122107105Srwatson
123182063Srwatson	if (p->p_label != NULL) {
124182063Srwatson		mac_proc_label_free(p->p_label);
125182063Srwatson		p->p_label = NULL;
126182063Srwatson	}
127107105Srwatson}
128107105Srwatson
129184407Srwatsonvoid
130104522Srwatsonmac_thread_userret(struct thread *td)
131104522Srwatson{
132104522Srwatson
133191731Srwatson	MAC_POLICY_PERFORM(thread_userret, td);
134104522Srwatson}
135104522Srwatson
136105988Srwatsonint
137122524Srwatsonmac_execve_enter(struct image_params *imgp, struct mac *mac_p)
138106468Srwatson{
139122524Srwatson	struct label *label;
140106468Srwatson	struct mac mac;
141106468Srwatson	char *buffer;
142106468Srwatson	int error;
143106468Srwatson
144106468Srwatson	if (mac_p == NULL)
145106468Srwatson		return (0);
146106468Srwatson
147182063Srwatson	if (!(mac_labeled & MPC_OBJECT_CRED))
148182063Srwatson		return (EINVAL);
149182063Srwatson
150106468Srwatson	error = copyin(mac_p, &mac, sizeof(mac));
151106468Srwatson	if (error)
152106468Srwatson		return (error);
153106468Srwatson
154106468Srwatson	error = mac_check_structmac_consistent(&mac);
155106468Srwatson	if (error)
156106468Srwatson		return (error);
157106468Srwatson
158111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
159106468Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
160106468Srwatson	if (error) {
161106468Srwatson		free(buffer, M_MACTEMP);
162106468Srwatson		return (error);
163106468Srwatson	}
164106468Srwatson
165122524Srwatson	label = mac_cred_label_alloc();
166172930Srwatson	error = mac_cred_internalize_label(label, buffer);
167106468Srwatson	free(buffer, M_MACTEMP);
168106468Srwatson	if (error) {
169122524Srwatson		mac_cred_label_free(label);
170106468Srwatson		return (error);
171106468Srwatson	}
172122524Srwatson	imgp->execlabel = label;
173106468Srwatson	return (0);
174106468Srwatson}
175106468Srwatson
176100979Srwatsonvoid
177106468Srwatsonmac_execve_exit(struct image_params *imgp)
178100979Srwatson{
179122524Srwatson	if (imgp->execlabel != NULL) {
180122524Srwatson		mac_cred_label_free(imgp->execlabel);
181122524Srwatson		imgp->execlabel = NULL;
182122524Srwatson	}
183106468Srwatson}
184100979Srwatson
185182063Srwatsonvoid
186182063Srwatsonmac_execve_interpreter_enter(struct vnode *interpvp,
187182063Srwatson    struct label **interpvplabel)
188182063Srwatson{
189182063Srwatson
190182063Srwatson	if (mac_labeled & MPC_OBJECT_VNODE) {
191182063Srwatson		*interpvplabel = mac_vnode_label_alloc();
192182063Srwatson		mac_vnode_copy_label(interpvp->v_label, *interpvplabel);
193182063Srwatson	} else
194182063Srwatson		*interpvplabel = NULL;
195182063Srwatson}
196182063Srwatson
197182063Srwatsonvoid
198182063Srwatsonmac_execve_interpreter_exit(struct label *interpvplabel)
199182063Srwatson{
200182063Srwatson
201182063Srwatson	if (interpvplabel != NULL)
202182063Srwatson		mac_vnode_label_free(interpvplabel);
203182063Srwatson}
204182063Srwatson
205100979Srwatson/*
206100979Srwatson * When relabeling a process, call out to the policies for the maximum
207165425Srwatson * permission allowed for each object type we know about in its memory space,
208165425Srwatson * and revoke access (in the least surprising ways we know) when necessary.
209165425Srwatson * The process lock is not held here.
210100979Srwatson */
211107271Srwatsonvoid
212184412Srwatsonmac_proc_vm_revoke(struct thread *td)
213100979Srwatson{
214184412Srwatson	struct ucred *cred;
215100979Srwatson
216184412Srwatson	PROC_LOCK(td->td_proc);
217184412Srwatson	cred = crhold(td->td_proc->p_ucred);
218184412Srwatson	PROC_UNLOCK(td->td_proc);
219184412Srwatson
220100979Srwatson	/* XXX freeze all other threads */
221184412Srwatson	mac_proc_vm_revoke_recurse(td, cred,
222100979Srwatson	    &td->td_proc->p_vmspace->vm_map);
223100979Srwatson	/* XXX allow other threads to continue */
224184412Srwatson
225184412Srwatson	crfree(cred);
226100979Srwatson}
227100979Srwatson
228100979Srwatsonstatic __inline const char *
229100979Srwatsonprot2str(vm_prot_t prot)
230100979Srwatson{
231100979Srwatson
232100979Srwatson	switch (prot & VM_PROT_ALL) {
233100979Srwatson	case VM_PROT_READ:
234100979Srwatson		return ("r--");
235100979Srwatson	case VM_PROT_READ | VM_PROT_WRITE:
236100979Srwatson		return ("rw-");
237100979Srwatson	case VM_PROT_READ | VM_PROT_EXECUTE:
238100979Srwatson		return ("r-x");
239100979Srwatson	case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
240100979Srwatson		return ("rwx");
241100979Srwatson	case VM_PROT_WRITE:
242100979Srwatson		return ("-w-");
243100979Srwatson	case VM_PROT_EXECUTE:
244100979Srwatson		return ("--x");
245100979Srwatson	case VM_PROT_WRITE | VM_PROT_EXECUTE:
246100979Srwatson		return ("-wx");
247100979Srwatson	default:
248100979Srwatson		return ("---");
249100979Srwatson	}
250100979Srwatson}
251100979Srwatson
252100979Srwatsonstatic void
253184412Srwatsonmac_proc_vm_revoke_recurse(struct thread *td, struct ucred *cred,
254100979Srwatson    struct vm_map *map)
255100979Srwatson{
256189013Skib	vm_map_entry_t vme;
257150913Scsjp	int vfslocked, result;
258104546Srwatson	vm_prot_t revokeperms;
259151115Scsjp	vm_object_t backing_object, object;
260100979Srwatson	vm_ooffset_t offset;
261100979Srwatson	struct vnode *vp;
262156225Stegge	struct mount *mp;
263100979Srwatson
264103136Srwatson	if (!mac_mmap_revocation)
265103136Srwatson		return;
266103136Srwatson
267186397Salc	vm_map_lock(map);
268100979Srwatson	for (vme = map->header.next; vme != &map->header; vme = vme->next) {
269100979Srwatson		if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
270184412Srwatson			mac_proc_vm_revoke_recurse(td, cred,
271100979Srwatson			    vme->object.sub_map);
272100979Srwatson			continue;
273100979Srwatson		}
274100979Srwatson		/*
275100979Srwatson		 * Skip over entries that obviously are not shared.
276100979Srwatson		 */
277100979Srwatson		if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) ||
278100979Srwatson		    !vme->max_protection)
279100979Srwatson			continue;
280100979Srwatson		/*
281100979Srwatson		 * Drill down to the deepest backing object.
282100979Srwatson		 */
283100979Srwatson		offset = vme->offset;
284100979Srwatson		object = vme->object.vm_object;
285100979Srwatson		if (object == NULL)
286100979Srwatson			continue;
287151115Scsjp		VM_OBJECT_LOCK(object);
288151115Scsjp		while ((backing_object = object->backing_object) != NULL) {
289151115Scsjp			VM_OBJECT_LOCK(backing_object);
290150923Scsjp			offset += object->backing_object_offset;
291151115Scsjp			VM_OBJECT_UNLOCK(object);
292151115Scsjp			object = backing_object;
293100979Srwatson		}
294151115Scsjp		VM_OBJECT_UNLOCK(object);
295100979Srwatson		/*
296165425Srwatson		 * At the moment, vm_maps and objects aren't considered by
297165425Srwatson		 * the MAC system, so only things with backing by a normal
298165425Srwatson		 * object (read: vnodes) are checked.
299100979Srwatson		 */
300100979Srwatson		if (object->type != OBJT_VNODE)
301100979Srwatson			continue;
302100979Srwatson		vp = (struct vnode *)object->handle;
303150913Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
304175202Sattilio		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
305104546Srwatson		result = vme->max_protection;
306172930Srwatson		mac_vnode_check_mmap_downgrade(cred, vp, &result);
307175294Sattilio		VOP_UNLOCK(vp, 0);
308100979Srwatson		/*
309165425Srwatson		 * Find out what maximum protection we may be allowing now
310165425Srwatson		 * but a policy needs to get removed.
311100979Srwatson		 */
312100979Srwatson		revokeperms = vme->max_protection & ~result;
313150913Scsjp		if (!revokeperms) {
314150913Scsjp			VFS_UNLOCK_GIANT(vfslocked);
315100979Srwatson			continue;
316150913Scsjp		}
317102949Sbde		printf("pid %ld: revoking %s perms from %#lx:%ld "
318102949Sbde		    "(max %s/cur %s)\n", (long)td->td_proc->p_pid,
319102949Sbde		    prot2str(revokeperms), (u_long)vme->start,
320102949Sbde		    (long)(vme->end - vme->start),
321100979Srwatson		    prot2str(vme->max_protection), prot2str(vme->protection));
322100979Srwatson		/*
323100979Srwatson		 * This is the really simple case: if a map has more
324100979Srwatson		 * max_protection than is allowed, but it's not being
325165425Srwatson		 * actually used (that is, the current protection is still
326165425Srwatson		 * allowed), we can just wipe it out and do nothing more.
327100979Srwatson		 */
328100979Srwatson		if ((vme->protection & revokeperms) == 0) {
329100979Srwatson			vme->max_protection -= revokeperms;
330100979Srwatson		} else {
331100979Srwatson			if (revokeperms & VM_PROT_WRITE) {
332100979Srwatson				/*
333100979Srwatson				 * In the more complicated case, flush out all
334100979Srwatson				 * pending changes to the object then turn it
335100979Srwatson				 * copy-on-write.
336100979Srwatson				 */
337100979Srwatson				vm_object_reference(object);
338156225Stegge				(void) vn_start_write(vp, &mp, V_WAIT);
339175202Sattilio				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
340113955Salc				VM_OBJECT_LOCK(object);
341218345Salc				vm_object_page_clean(object, offset, offset +
342218345Salc				    vme->end - vme->start, OBJPC_SYNC);
343113955Salc				VM_OBJECT_UNLOCK(object);
344175294Sattilio				VOP_UNLOCK(vp, 0);
345156225Stegge				vn_finished_write(mp);
346100979Srwatson				vm_object_deallocate(object);
347100979Srwatson				/*
348100979Srwatson				 * Why bother if there's no read permissions
349100979Srwatson				 * anymore?  For the rest, we need to leave
350100979Srwatson				 * the write permissions on for COW, or
351100979Srwatson				 * remove them entirely if configured to.
352100979Srwatson				 */
353100979Srwatson				if (!mac_mmap_revocation_via_cow) {
354100979Srwatson					vme->max_protection &= ~VM_PROT_WRITE;
355100979Srwatson					vme->protection &= ~VM_PROT_WRITE;
356100979Srwatson				} if ((revokeperms & VM_PROT_READ) == 0)
357100979Srwatson					vme->eflags |= MAP_ENTRY_COW |
358100979Srwatson					    MAP_ENTRY_NEEDS_COPY;
359100979Srwatson			}
360100979Srwatson			if (revokeperms & VM_PROT_EXECUTE) {
361100979Srwatson				vme->max_protection &= ~VM_PROT_EXECUTE;
362100979Srwatson				vme->protection &= ~VM_PROT_EXECUTE;
363100979Srwatson			}
364100979Srwatson			if (revokeperms & VM_PROT_READ) {
365100979Srwatson				vme->max_protection = 0;
366100979Srwatson				vme->protection = 0;
367100979Srwatson			}
368100979Srwatson			pmap_protect(map->pmap, vme->start, vme->end,
369100979Srwatson			    vme->protection & ~revokeperms);
370100979Srwatson			vm_map_simplify_entry(map, vme);
371100979Srwatson		}
372150913Scsjp		VFS_UNLOCK_GIANT(vfslocked);
373100979Srwatson	}
374186397Salc	vm_map_unlock(map);
375100979Srwatson}
376100979Srwatson
377189503SrwatsonMAC_CHECK_PROBE_DEFINE2(proc_check_debug, "struct ucred *", "struct proc *");
378189503Srwatson
379100979Srwatsonint
380172930Srwatsonmac_proc_check_debug(struct ucred *cred, struct proc *p)
381100979Srwatson{
382100979Srwatson	int error;
383100979Srwatson
384168955Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
385102103Srwatson
386191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(proc_check_debug, cred, p);
387189503Srwatson	MAC_CHECK_PROBE2(proc_check_debug, error, cred, p);
388100979Srwatson
389100979Srwatson	return (error);
390100979Srwatson}
391100979Srwatson
392189503SrwatsonMAC_CHECK_PROBE_DEFINE2(proc_check_sched, "struct ucred *", "struct proc *");
393189503Srwatson
394100979Srwatsonint
395172930Srwatsonmac_proc_check_sched(struct ucred *cred, struct proc *p)
396100979Srwatson{
397100979Srwatson	int error;
398100979Srwatson
399168955Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
400102103Srwatson
401191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(proc_check_sched, cred, p);
402189503Srwatson	MAC_CHECK_PROBE2(proc_check_sched, error, cred, p);
403100979Srwatson
404100979Srwatson	return (error);
405100979Srwatson}
406100979Srwatson
407189503SrwatsonMAC_CHECK_PROBE_DEFINE3(proc_check_signal, "struct ucred *", "struct proc *",
408189503Srwatson    "int");
409189503Srwatson
410100979Srwatsonint
411172930Srwatsonmac_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
412100979Srwatson{
413100979Srwatson	int error;
414100979Srwatson
415168955Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
416102103Srwatson
417191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(proc_check_signal, cred, p, signum);
418189503Srwatson	MAC_CHECK_PROBE3(proc_check_signal, error, cred, p, signum);
419100979Srwatson
420100979Srwatson	return (error);
421100979Srwatson}
422145147Srwatson
423189503SrwatsonMAC_CHECK_PROBE_DEFINE2(proc_check_wait, "struct ucred *", "struct proc *");
424189503Srwatson
425145234Srwatsonint
426172930Srwatsonmac_proc_check_wait(struct ucred *cred, struct proc *p)
427145234Srwatson{
428145234Srwatson	int error;
429145234Srwatson
430168955Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
431145234Srwatson
432191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(proc_check_wait, cred, p);
433189503Srwatson	MAC_CHECK_PROBE2(proc_check_wait, error, cred, p);
434145234Srwatson
435145234Srwatson	return (error);
436145234Srwatson}
437