mac_process.c revision 189797
1/*-
2 * Copyright (c) 1999-2002, 2008-2009 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
5 * Copyright (c) 2006 SPARTA, Inc.
6 * Copyright (c) 2008 Apple Inc.
7 * All rights reserved.
8 *
9 * This software was developed by Robert Watson and Ilmar Habibulin for the
10 * TrustedBSD Project.
11 *
12 * This software was developed for the FreeBSD Project in part by Network
13 * Associates Laboratories, the Security Research Division of Network
14 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15 * as part of the DARPA CHATS research program.
16 *
17 * This software was enhanced by SPARTA ISSO under SPAWAR contract
18 * N66001-04-C-6019 ("SEFOS").
19 *
20 * This software was developed at the University of Cambridge Computer
21 * Laboratory with support from a grant from Google, Inc.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 */
44
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: head/sys/security/mac/mac_process.c 189797 2009-03-14 16:06:06Z rwatson $");
47
48#include "opt_kdtrace.h"
49#include "opt_mac.h"
50
51#include <sys/param.h>
52#include <sys/condvar.h>
53#include <sys/imgact.h>
54#include <sys/kernel.h>
55#include <sys/lock.h>
56#include <sys/malloc.h>
57#include <sys/mutex.h>
58#include <sys/mac.h>
59#include <sys/proc.h>
60#include <sys/sbuf.h>
61#include <sys/sdt.h>
62#include <sys/systm.h>
63#include <sys/vnode.h>
64#include <sys/mount.h>
65#include <sys/file.h>
66#include <sys/namei.h>
67#include <sys/sysctl.h>
68
69#include <vm/vm.h>
70#include <vm/pmap.h>
71#include <vm/vm_map.h>
72#include <vm/vm_object.h>
73
74#include <security/mac/mac_framework.h>
75#include <security/mac/mac_internal.h>
76#include <security/mac/mac_policy.h>
77
78static int	mac_mmap_revocation = 1;
79SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW,
80    &mac_mmap_revocation, 0, "Revoke mmap access to files on subject "
81    "relabel");
82
83static int	mac_mmap_revocation_via_cow = 0;
84SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW,
85    &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via "
86    "copy-on-write semantics, or by removing all write access");
87
88static void	mac_proc_vm_revoke_recurse(struct thread *td,
89		    struct ucred *cred, struct vm_map *map);
90
91static struct label *
92mac_proc_label_alloc(void)
93{
94	struct label *label;
95
96	label = mac_labelzone_alloc(M_WAITOK);
97	MAC_PERFORM(proc_init_label, label);
98	return (label);
99}
100
101void
102mac_proc_init(struct proc *p)
103{
104
105	if (mac_labeled & MPC_OBJECT_PROC)
106		p->p_label = mac_proc_label_alloc();
107	else
108		p->p_label = NULL;
109}
110
111static void
112mac_proc_label_free(struct label *label)
113{
114
115	MAC_PERFORM_NOSLEEP(proc_destroy_label, label);
116	mac_labelzone_free(label);
117}
118
119void
120mac_proc_destroy(struct proc *p)
121{
122
123	if (p->p_label != NULL) {
124		mac_proc_label_free(p->p_label);
125		p->p_label = NULL;
126	}
127}
128
129void
130mac_thread_userret(struct thread *td)
131{
132
133	MAC_PERFORM(thread_userret, td);
134}
135
136int
137mac_execve_enter(struct image_params *imgp, struct mac *mac_p)
138{
139	struct label *label;
140	struct mac mac;
141	char *buffer;
142	int error;
143
144	if (mac_p == NULL)
145		return (0);
146
147	if (!(mac_labeled & MPC_OBJECT_CRED))
148		return (EINVAL);
149
150	error = copyin(mac_p, &mac, sizeof(mac));
151	if (error)
152		return (error);
153
154	error = mac_check_structmac_consistent(&mac);
155	if (error)
156		return (error);
157
158	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
159	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
160	if (error) {
161		free(buffer, M_MACTEMP);
162		return (error);
163	}
164
165	label = mac_cred_label_alloc();
166	error = mac_cred_internalize_label(label, buffer);
167	free(buffer, M_MACTEMP);
168	if (error) {
169		mac_cred_label_free(label);
170		return (error);
171	}
172	imgp->execlabel = label;
173	return (0);
174}
175
176void
177mac_execve_exit(struct image_params *imgp)
178{
179	if (imgp->execlabel != NULL) {
180		mac_cred_label_free(imgp->execlabel);
181		imgp->execlabel = NULL;
182	}
183}
184
185void
186mac_execve_interpreter_enter(struct vnode *interpvp,
187    struct label **interpvplabel)
188{
189
190	if (mac_labeled & MPC_OBJECT_VNODE) {
191		*interpvplabel = mac_vnode_label_alloc();
192		mac_vnode_copy_label(interpvp->v_label, *interpvplabel);
193	} else
194		*interpvplabel = NULL;
195}
196
197void
198mac_execve_interpreter_exit(struct label *interpvplabel)
199{
200
201	if (interpvplabel != NULL)
202		mac_vnode_label_free(interpvplabel);
203}
204
205/*
206 * When relabeling a process, call out to the policies for the maximum
207 * permission allowed for each object type we know about in its memory space,
208 * and revoke access (in the least surprising ways we know) when necessary.
209 * The process lock is not held here.
210 */
211void
212mac_proc_vm_revoke(struct thread *td)
213{
214	struct ucred *cred;
215
216	PROC_LOCK(td->td_proc);
217	cred = crhold(td->td_proc->p_ucred);
218	PROC_UNLOCK(td->td_proc);
219
220	/* XXX freeze all other threads */
221	mac_proc_vm_revoke_recurse(td, cred,
222	    &td->td_proc->p_vmspace->vm_map);
223	/* XXX allow other threads to continue */
224
225	crfree(cred);
226}
227
228static __inline const char *
229prot2str(vm_prot_t prot)
230{
231
232	switch (prot & VM_PROT_ALL) {
233	case VM_PROT_READ:
234		return ("r--");
235	case VM_PROT_READ | VM_PROT_WRITE:
236		return ("rw-");
237	case VM_PROT_READ | VM_PROT_EXECUTE:
238		return ("r-x");
239	case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
240		return ("rwx");
241	case VM_PROT_WRITE:
242		return ("-w-");
243	case VM_PROT_EXECUTE:
244		return ("--x");
245	case VM_PROT_WRITE | VM_PROT_EXECUTE:
246		return ("-wx");
247	default:
248		return ("---");
249	}
250}
251
252static void
253mac_proc_vm_revoke_recurse(struct thread *td, struct ucred *cred,
254    struct vm_map *map)
255{
256	vm_map_entry_t vme;
257	int vfslocked, result;
258	vm_prot_t revokeperms;
259	vm_object_t backing_object, object;
260	vm_ooffset_t offset;
261	struct vnode *vp;
262	struct mount *mp;
263
264	if (!mac_mmap_revocation)
265		return;
266
267	vm_map_lock(map);
268	for (vme = map->header.next; vme != &map->header; vme = vme->next) {
269		if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
270			mac_proc_vm_revoke_recurse(td, cred,
271			    vme->object.sub_map);
272			continue;
273		}
274		/*
275		 * Skip over entries that obviously are not shared.
276		 */
277		if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) ||
278		    !vme->max_protection)
279			continue;
280		/*
281		 * Drill down to the deepest backing object.
282		 */
283		offset = vme->offset;
284		object = vme->object.vm_object;
285		if (object == NULL)
286			continue;
287		VM_OBJECT_LOCK(object);
288		while ((backing_object = object->backing_object) != NULL) {
289			VM_OBJECT_LOCK(backing_object);
290			offset += object->backing_object_offset;
291			VM_OBJECT_UNLOCK(object);
292			object = backing_object;
293		}
294		VM_OBJECT_UNLOCK(object);
295		/*
296		 * At the moment, vm_maps and objects aren't considered by
297		 * the MAC system, so only things with backing by a normal
298		 * object (read: vnodes) are checked.
299		 */
300		if (object->type != OBJT_VNODE)
301			continue;
302		vp = (struct vnode *)object->handle;
303		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
304		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
305		result = vme->max_protection;
306		mac_vnode_check_mmap_downgrade(cred, vp, &result);
307		VOP_UNLOCK(vp, 0);
308		/*
309		 * Find out what maximum protection we may be allowing now
310		 * but a policy needs to get removed.
311		 */
312		revokeperms = vme->max_protection & ~result;
313		if (!revokeperms) {
314			VFS_UNLOCK_GIANT(vfslocked);
315			continue;
316		}
317		printf("pid %ld: revoking %s perms from %#lx:%ld "
318		    "(max %s/cur %s)\n", (long)td->td_proc->p_pid,
319		    prot2str(revokeperms), (u_long)vme->start,
320		    (long)(vme->end - vme->start),
321		    prot2str(vme->max_protection), prot2str(vme->protection));
322		/*
323		 * This is the really simple case: if a map has more
324		 * max_protection than is allowed, but it's not being
325		 * actually used (that is, the current protection is still
326		 * allowed), we can just wipe it out and do nothing more.
327		 */
328		if ((vme->protection & revokeperms) == 0) {
329			vme->max_protection -= revokeperms;
330		} else {
331			if (revokeperms & VM_PROT_WRITE) {
332				/*
333				 * In the more complicated case, flush out all
334				 * pending changes to the object then turn it
335				 * copy-on-write.
336				 */
337				vm_object_reference(object);
338				(void) vn_start_write(vp, &mp, V_WAIT);
339				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
340				VM_OBJECT_LOCK(object);
341				vm_object_page_clean(object,
342				    OFF_TO_IDX(offset),
343				    OFF_TO_IDX(offset + vme->end - vme->start +
344					PAGE_MASK),
345				    OBJPC_SYNC);
346				VM_OBJECT_UNLOCK(object);
347				VOP_UNLOCK(vp, 0);
348				vn_finished_write(mp);
349				vm_object_deallocate(object);
350				/*
351				 * Why bother if there's no read permissions
352				 * anymore?  For the rest, we need to leave
353				 * the write permissions on for COW, or
354				 * remove them entirely if configured to.
355				 */
356				if (!mac_mmap_revocation_via_cow) {
357					vme->max_protection &= ~VM_PROT_WRITE;
358					vme->protection &= ~VM_PROT_WRITE;
359				} if ((revokeperms & VM_PROT_READ) == 0)
360					vme->eflags |= MAP_ENTRY_COW |
361					    MAP_ENTRY_NEEDS_COPY;
362			}
363			if (revokeperms & VM_PROT_EXECUTE) {
364				vme->max_protection &= ~VM_PROT_EXECUTE;
365				vme->protection &= ~VM_PROT_EXECUTE;
366			}
367			if (revokeperms & VM_PROT_READ) {
368				vme->max_protection = 0;
369				vme->protection = 0;
370			}
371			pmap_protect(map->pmap, vme->start, vme->end,
372			    vme->protection & ~revokeperms);
373			vm_map_simplify_entry(map, vme);
374		}
375		VFS_UNLOCK_GIANT(vfslocked);
376	}
377	vm_map_unlock(map);
378}
379
380MAC_CHECK_PROBE_DEFINE2(proc_check_debug, "struct ucred *", "struct proc *");
381
382int
383mac_proc_check_debug(struct ucred *cred, struct proc *p)
384{
385	int error;
386
387	PROC_LOCK_ASSERT(p, MA_OWNED);
388
389	MAC_CHECK_NOSLEEP(proc_check_debug, cred, p);
390	MAC_CHECK_PROBE2(proc_check_debug, error, cred, p);
391
392	return (error);
393}
394
395MAC_CHECK_PROBE_DEFINE2(proc_check_sched, "struct ucred *", "struct proc *");
396
397int
398mac_proc_check_sched(struct ucred *cred, struct proc *p)
399{
400	int error;
401
402	PROC_LOCK_ASSERT(p, MA_OWNED);
403
404	MAC_CHECK_NOSLEEP(proc_check_sched, cred, p);
405	MAC_CHECK_PROBE2(proc_check_sched, error, cred, p);
406
407	return (error);
408}
409
410MAC_CHECK_PROBE_DEFINE3(proc_check_signal, "struct ucred *", "struct proc *",
411    "int");
412
413int
414mac_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
415{
416	int error;
417
418	PROC_LOCK_ASSERT(p, MA_OWNED);
419
420	MAC_CHECK_NOSLEEP(proc_check_signal, cred, p, signum);
421	MAC_CHECK_PROBE3(proc_check_signal, error, cred, p, signum);
422
423	return (error);
424}
425
426MAC_CHECK_PROBE_DEFINE2(proc_check_wait, "struct ucred *", "struct proc *");
427
428int
429mac_proc_check_wait(struct ucred *cred, struct proc *p)
430{
431	int error;
432
433	PROC_LOCK_ASSERT(p, MA_OWNED);
434
435	MAC_CHECK_NOSLEEP(proc_check_wait, cred, p);
436	MAC_CHECK_PROBE2(proc_check_wait, error, cred, p);
437
438	return (error);
439}
440