xref: /freebsd/sys/security/mac/mac_process.c (revision 9e51595ce660d915899019d03075d8c17f3732d3)
1 /*-
2  * Copyright (c) 1999-2002 Robert N. M. Watson
3  * Copyright (c) 2001 Ilmar S. Habibulin
4  * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
5  * Copyright (c) 2005 Samy Al Bahra
6  * Copyright (c) 2006 SPARTA, Inc.
7  * Copyright (c) 2008 Apple Inc.
8  * All rights reserved.
9  *
10  * This software was developed by Robert Watson and Ilmar Habibulin for the
11  * TrustedBSD Project.
12  *
13  * This software was developed for the FreeBSD Project in part by Network
14  * Associates Laboratories, the Security Research Division of Network
15  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
16  * as part of the DARPA CHATS research program.
17  *
18  * This software was enhanced by SPARTA ISSO under SPAWAR contract
19  * N66001-04-C-6019 ("SEFOS").
20  *
21  * Redistribution and use in source and binary forms, with or without
22  * modification, are permitted provided that the following conditions
23  * are met:
24  * 1. Redistributions of source code must retain the above copyright
25  *    notice, this list of conditions and the following disclaimer.
26  * 2. Redistributions in binary form must reproduce the above copyright
27  *    notice, this list of conditions and the following disclaimer in the
28  *    documentation and/or other materials provided with the distribution.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  */
42 
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45 
46 #include "opt_mac.h"
47 
48 #include <sys/param.h>
49 #include <sys/condvar.h>
50 #include <sys/imgact.h>
51 #include <sys/kernel.h>
52 #include <sys/lock.h>
53 #include <sys/malloc.h>
54 #include <sys/mutex.h>
55 #include <sys/mac.h>
56 #include <sys/proc.h>
57 #include <sys/sbuf.h>
58 #include <sys/systm.h>
59 #include <sys/vnode.h>
60 #include <sys/mount.h>
61 #include <sys/file.h>
62 #include <sys/namei.h>
63 #include <sys/sysctl.h>
64 
65 #include <vm/vm.h>
66 #include <vm/pmap.h>
67 #include <vm/vm_map.h>
68 #include <vm/vm_object.h>
69 
70 #include <security/mac/mac_framework.h>
71 #include <security/mac/mac_internal.h>
72 #include <security/mac/mac_policy.h>
73 
74 static int	mac_mmap_revocation = 1;
75 SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW,
76     &mac_mmap_revocation, 0, "Revoke mmap access to files on subject "
77     "relabel");
78 
79 static int	mac_mmap_revocation_via_cow = 0;
80 SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW,
81     &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via "
82     "copy-on-write semantics, or by removing all write access");
83 
84 static void	mac_cred_mmapped_drop_perms_recurse(struct thread *td,
85 		    struct ucred *cred, struct vm_map *map);
86 
87 struct label *
88 mac_cred_label_alloc(void)
89 {
90 	struct label *label;
91 
92 	label = mac_labelzone_alloc(M_WAITOK);
93 	MAC_PERFORM(cred_init_label, label);
94 	return (label);
95 }
96 
97 void
98 mac_cred_init(struct ucred *cred)
99 {
100 
101 	if (mac_labeled & MPC_OBJECT_CRED)
102 		cred->cr_label = mac_cred_label_alloc();
103 	else
104 		cred->cr_label = NULL;
105 }
106 
107 static struct label *
108 mac_proc_label_alloc(void)
109 {
110 	struct label *label;
111 
112 	label = mac_labelzone_alloc(M_WAITOK);
113 	MAC_PERFORM(proc_init_label, label);
114 	return (label);
115 }
116 
117 void
118 mac_proc_init(struct proc *p)
119 {
120 
121 	if (mac_labeled & MPC_OBJECT_PROC)
122 		p->p_label = mac_proc_label_alloc();
123 	else
124 		p->p_label = NULL;
125 }
126 
127 void
128 mac_cred_label_free(struct label *label)
129 {
130 
131 	MAC_PERFORM(cred_destroy_label, label);
132 	mac_labelzone_free(label);
133 }
134 
135 void
136 mac_cred_destroy(struct ucred *cred)
137 {
138 
139 	if (cred->cr_label != NULL) {
140 		mac_cred_label_free(cred->cr_label);
141 		cred->cr_label = NULL;
142 	}
143 }
144 
145 static void
146 mac_proc_label_free(struct label *label)
147 {
148 
149 	MAC_PERFORM(proc_destroy_label, label);
150 	mac_labelzone_free(label);
151 }
152 
153 void
154 mac_proc_destroy(struct proc *p)
155 {
156 
157 	if (p->p_label != NULL) {
158 		mac_proc_label_free(p->p_label);
159 		p->p_label = NULL;
160 	}
161 }
162 
163 int
164 mac_cred_externalize_label(struct label *label, char *elements,
165     char *outbuf, size_t outbuflen)
166 {
167 	int error;
168 
169 	MAC_EXTERNALIZE(cred, label, elements, outbuf, outbuflen);
170 
171 	return (error);
172 }
173 
174 int
175 mac_cred_internalize_label(struct label *label, char *string)
176 {
177 	int error;
178 
179 	MAC_INTERNALIZE(cred, label, string);
180 
181 	return (error);
182 }
183 
184 /*
185  * Initialize MAC label for the first kernel process, from which other kernel
186  * processes and threads are spawned.
187  */
188 void
189 mac_proc_create_swapper(struct ucred *cred)
190 {
191 
192 	MAC_PERFORM(proc_create_swapper, cred);
193 }
194 
195 /*
196  * Initialize MAC label for the first userland process, from which other
197  * userland processes and threads are spawned.
198  */
199 void
200 mac_proc_create_init(struct ucred *cred)
201 {
202 
203 	MAC_PERFORM(proc_create_init, cred);
204 }
205 
206 /*
207  * When a thread becomes an NFS server daemon, its credential may need to be
208  * updated to reflect this so that policies can recognize when file system
209  * operations originate from the network.
210  *
211  * At some point, it would be desirable if the credential used for each NFS
212  * RPC could be set based on the RPC context (i.e., source system, etc) to
213  * provide more fine-grained access control.
214  */
215 void
216 mac_proc_associate_nfsd(struct ucred *cred)
217 {
218 
219 	MAC_PERFORM(proc_associate_nfsd, cred);
220 }
221 
222 void
223 mac_thread_userret(struct thread *td)
224 {
225 
226 	MAC_PERFORM(thread_userret, td);
227 }
228 
229 /*
230  * When a new process is created, its label must be initialized.  Generally,
231  * this involves inheritence from the parent process, modulo possible deltas.
232  * This function allows that processing to take place.
233  */
234 void
235 mac_cred_copy(struct ucred *src, struct ucred *dest)
236 {
237 
238 	MAC_PERFORM(cred_copy_label, src->cr_label, dest->cr_label);
239 }
240 
241 int
242 mac_execve_enter(struct image_params *imgp, struct mac *mac_p)
243 {
244 	struct label *label;
245 	struct mac mac;
246 	char *buffer;
247 	int error;
248 
249 	if (mac_p == NULL)
250 		return (0);
251 
252 	if (!(mac_labeled & MPC_OBJECT_CRED))
253 		return (EINVAL);
254 
255 	error = copyin(mac_p, &mac, sizeof(mac));
256 	if (error)
257 		return (error);
258 
259 	error = mac_check_structmac_consistent(&mac);
260 	if (error)
261 		return (error);
262 
263 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
264 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
265 	if (error) {
266 		free(buffer, M_MACTEMP);
267 		return (error);
268 	}
269 
270 	label = mac_cred_label_alloc();
271 	error = mac_cred_internalize_label(label, buffer);
272 	free(buffer, M_MACTEMP);
273 	if (error) {
274 		mac_cred_label_free(label);
275 		return (error);
276 	}
277 	imgp->execlabel = label;
278 	return (0);
279 }
280 
281 void
282 mac_execve_exit(struct image_params *imgp)
283 {
284 	if (imgp->execlabel != NULL) {
285 		mac_cred_label_free(imgp->execlabel);
286 		imgp->execlabel = NULL;
287 	}
288 }
289 
290 void
291 mac_execve_interpreter_enter(struct vnode *interpvp,
292     struct label **interpvplabel)
293 {
294 
295 	if (mac_labeled & MPC_OBJECT_VNODE) {
296 		*interpvplabel = mac_vnode_label_alloc();
297 		mac_vnode_copy_label(interpvp->v_label, *interpvplabel);
298 	} else
299 		*interpvplabel = NULL;
300 }
301 
302 void
303 mac_execve_interpreter_exit(struct label *interpvplabel)
304 {
305 
306 	if (interpvplabel != NULL)
307 		mac_vnode_label_free(interpvplabel);
308 }
309 
310 /*
311  * When relabeling a process, call out to the policies for the maximum
312  * permission allowed for each object type we know about in its memory space,
313  * and revoke access (in the least surprising ways we know) when necessary.
314  * The process lock is not held here.
315  */
316 void
317 mac_cred_mmapped_drop_perms(struct thread *td, struct ucred *cred)
318 {
319 
320 	/* XXX freeze all other threads */
321 	mac_cred_mmapped_drop_perms_recurse(td, cred,
322 	    &td->td_proc->p_vmspace->vm_map);
323 	/* XXX allow other threads to continue */
324 }
325 
326 static __inline const char *
327 prot2str(vm_prot_t prot)
328 {
329 
330 	switch (prot & VM_PROT_ALL) {
331 	case VM_PROT_READ:
332 		return ("r--");
333 	case VM_PROT_READ | VM_PROT_WRITE:
334 		return ("rw-");
335 	case VM_PROT_READ | VM_PROT_EXECUTE:
336 		return ("r-x");
337 	case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
338 		return ("rwx");
339 	case VM_PROT_WRITE:
340 		return ("-w-");
341 	case VM_PROT_EXECUTE:
342 		return ("--x");
343 	case VM_PROT_WRITE | VM_PROT_EXECUTE:
344 		return ("-wx");
345 	default:
346 		return ("---");
347 	}
348 }
349 
350 static void
351 mac_cred_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred,
352     struct vm_map *map)
353 {
354 	struct vm_map_entry *vme;
355 	int vfslocked, result;
356 	vm_prot_t revokeperms;
357 	vm_object_t backing_object, object;
358 	vm_ooffset_t offset;
359 	struct vnode *vp;
360 	struct mount *mp;
361 
362 	if (!mac_mmap_revocation)
363 		return;
364 
365 	vm_map_lock_read(map);
366 	for (vme = map->header.next; vme != &map->header; vme = vme->next) {
367 		if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
368 			mac_cred_mmapped_drop_perms_recurse(td, cred,
369 			    vme->object.sub_map);
370 			continue;
371 		}
372 		/*
373 		 * Skip over entries that obviously are not shared.
374 		 */
375 		if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) ||
376 		    !vme->max_protection)
377 			continue;
378 		/*
379 		 * Drill down to the deepest backing object.
380 		 */
381 		offset = vme->offset;
382 		object = vme->object.vm_object;
383 		if (object == NULL)
384 			continue;
385 		VM_OBJECT_LOCK(object);
386 		while ((backing_object = object->backing_object) != NULL) {
387 			VM_OBJECT_LOCK(backing_object);
388 			offset += object->backing_object_offset;
389 			VM_OBJECT_UNLOCK(object);
390 			object = backing_object;
391 		}
392 		VM_OBJECT_UNLOCK(object);
393 		/*
394 		 * At the moment, vm_maps and objects aren't considered by
395 		 * the MAC system, so only things with backing by a normal
396 		 * object (read: vnodes) are checked.
397 		 */
398 		if (object->type != OBJT_VNODE)
399 			continue;
400 		vp = (struct vnode *)object->handle;
401 		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
402 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
403 		result = vme->max_protection;
404 		mac_vnode_check_mmap_downgrade(cred, vp, &result);
405 		VOP_UNLOCK(vp, 0);
406 		/*
407 		 * Find out what maximum protection we may be allowing now
408 		 * but a policy needs to get removed.
409 		 */
410 		revokeperms = vme->max_protection & ~result;
411 		if (!revokeperms) {
412 			VFS_UNLOCK_GIANT(vfslocked);
413 			continue;
414 		}
415 		printf("pid %ld: revoking %s perms from %#lx:%ld "
416 		    "(max %s/cur %s)\n", (long)td->td_proc->p_pid,
417 		    prot2str(revokeperms), (u_long)vme->start,
418 		    (long)(vme->end - vme->start),
419 		    prot2str(vme->max_protection), prot2str(vme->protection));
420 		vm_map_lock_upgrade(map);
421 		/*
422 		 * This is the really simple case: if a map has more
423 		 * max_protection than is allowed, but it's not being
424 		 * actually used (that is, the current protection is still
425 		 * allowed), we can just wipe it out and do nothing more.
426 		 */
427 		if ((vme->protection & revokeperms) == 0) {
428 			vme->max_protection -= revokeperms;
429 		} else {
430 			if (revokeperms & VM_PROT_WRITE) {
431 				/*
432 				 * In the more complicated case, flush out all
433 				 * pending changes to the object then turn it
434 				 * copy-on-write.
435 				 */
436 				vm_object_reference(object);
437 				(void) vn_start_write(vp, &mp, V_WAIT);
438 				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
439 				VM_OBJECT_LOCK(object);
440 				vm_object_page_clean(object,
441 				    OFF_TO_IDX(offset),
442 				    OFF_TO_IDX(offset + vme->end - vme->start +
443 					PAGE_MASK),
444 				    OBJPC_SYNC);
445 				VM_OBJECT_UNLOCK(object);
446 				VOP_UNLOCK(vp, 0);
447 				vn_finished_write(mp);
448 				vm_object_deallocate(object);
449 				/*
450 				 * Why bother if there's no read permissions
451 				 * anymore?  For the rest, we need to leave
452 				 * the write permissions on for COW, or
453 				 * remove them entirely if configured to.
454 				 */
455 				if (!mac_mmap_revocation_via_cow) {
456 					vme->max_protection &= ~VM_PROT_WRITE;
457 					vme->protection &= ~VM_PROT_WRITE;
458 				} if ((revokeperms & VM_PROT_READ) == 0)
459 					vme->eflags |= MAP_ENTRY_COW |
460 					    MAP_ENTRY_NEEDS_COPY;
461 			}
462 			if (revokeperms & VM_PROT_EXECUTE) {
463 				vme->max_protection &= ~VM_PROT_EXECUTE;
464 				vme->protection &= ~VM_PROT_EXECUTE;
465 			}
466 			if (revokeperms & VM_PROT_READ) {
467 				vme->max_protection = 0;
468 				vme->protection = 0;
469 			}
470 			pmap_protect(map->pmap, vme->start, vme->end,
471 			    vme->protection & ~revokeperms);
472 			vm_map_simplify_entry(map, vme);
473 		}
474 		vm_map_lock_downgrade(map);
475 		VFS_UNLOCK_GIANT(vfslocked);
476 	}
477 	vm_map_unlock_read(map);
478 }
479 
480 /*
481  * When the subject's label changes, it may require revocation of privilege
482  * to mapped objects.  This can't be done on-the-fly later with a unified
483  * buffer cache.
484  */
485 void
486 mac_cred_relabel(struct ucred *cred, struct label *newlabel)
487 {
488 
489 	MAC_PERFORM(cred_relabel, cred, newlabel);
490 }
491 
492 int
493 mac_cred_check_relabel(struct ucred *cred, struct label *newlabel)
494 {
495 	int error;
496 
497 	MAC_CHECK(cred_check_relabel, cred, newlabel);
498 
499 	return (error);
500 }
501 
502 int
503 mac_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
504 {
505 	int error;
506 
507 	MAC_CHECK(cred_check_visible, cr1, cr2);
508 
509 	return (error);
510 }
511 
512 int
513 mac_proc_check_debug(struct ucred *cred, struct proc *p)
514 {
515 	int error;
516 
517 	PROC_LOCK_ASSERT(p, MA_OWNED);
518 
519 	MAC_CHECK(proc_check_debug, cred, p);
520 
521 	return (error);
522 }
523 
524 int
525 mac_proc_check_sched(struct ucred *cred, struct proc *p)
526 {
527 	int error;
528 
529 	PROC_LOCK_ASSERT(p, MA_OWNED);
530 
531 	MAC_CHECK(proc_check_sched, cred, p);
532 
533 	return (error);
534 }
535 
536 int
537 mac_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
538 {
539 	int error;
540 
541 	PROC_LOCK_ASSERT(p, MA_OWNED);
542 
543 	MAC_CHECK(proc_check_signal, cred, p, signum);
544 
545 	return (error);
546 }
547 
548 int
549 mac_proc_check_setuid(struct proc *p, struct ucred *cred, uid_t uid)
550 {
551 	int error;
552 
553 	PROC_LOCK_ASSERT(p, MA_OWNED);
554 
555 	MAC_CHECK(proc_check_setuid, cred, uid);
556 	return (error);
557 }
558 
559 int
560 mac_proc_check_seteuid(struct proc *p, struct ucred *cred, uid_t euid)
561 {
562 	int error;
563 
564 	PROC_LOCK_ASSERT(p, MA_OWNED);
565 
566 	MAC_CHECK(proc_check_seteuid, cred, euid);
567 	return (error);
568 }
569 
570 int
571 mac_proc_check_setgid(struct proc *p, struct ucred *cred, gid_t gid)
572 {
573 	int error;
574 
575 	PROC_LOCK_ASSERT(p, MA_OWNED);
576 
577 	MAC_CHECK(proc_check_setgid, cred, gid);
578 
579 	return (error);
580 }
581 
582 int
583 mac_proc_check_setegid(struct proc *p, struct ucred *cred, gid_t egid)
584 {
585 	int error;
586 
587 	PROC_LOCK_ASSERT(p, MA_OWNED);
588 
589 	MAC_CHECK(proc_check_setegid, cred, egid);
590 
591 	return (error);
592 }
593 
594 int
595 mac_proc_check_setgroups(struct proc *p, struct ucred *cred, int ngroups,
596     gid_t *gidset)
597 {
598 	int error;
599 
600 	PROC_LOCK_ASSERT(p, MA_OWNED);
601 
602 	MAC_CHECK(proc_check_setgroups, cred, ngroups, gidset);
603 	return (error);
604 }
605 
606 int
607 mac_proc_check_setreuid(struct proc *p, struct ucred *cred, uid_t ruid,
608     uid_t euid)
609 {
610 	int error;
611 
612 	PROC_LOCK_ASSERT(p, MA_OWNED);
613 
614 	MAC_CHECK(proc_check_setreuid, cred, ruid, euid);
615 
616 	return (error);
617 }
618 
619 int
620 mac_proc_check_setregid(struct proc *proc, struct ucred *cred, gid_t rgid,
621     gid_t egid)
622 {
623 	int error;
624 
625 	PROC_LOCK_ASSERT(proc, MA_OWNED);
626 
627 	MAC_CHECK(proc_check_setregid, cred, rgid, egid);
628 
629 	return (error);
630 }
631 
632 int
633 mac_proc_check_setresuid(struct proc *p, struct ucred *cred, uid_t ruid,
634     uid_t euid, uid_t suid)
635 {
636 	int error;
637 
638 	PROC_LOCK_ASSERT(p, MA_OWNED);
639 
640 	MAC_CHECK(proc_check_setresuid, cred, ruid, euid, suid);
641 	return (error);
642 }
643 
644 int
645 mac_proc_check_setresgid(struct proc *p, struct ucred *cred, gid_t rgid,
646     gid_t egid, gid_t sgid)
647 {
648 	int error;
649 
650 	PROC_LOCK_ASSERT(p, MA_OWNED);
651 
652 	MAC_CHECK(proc_check_setresgid, cred, rgid, egid, sgid);
653 
654 	return (error);
655 }
656 
657 int
658 mac_proc_check_wait(struct ucred *cred, struct proc *p)
659 {
660 	int error;
661 
662 	PROC_LOCK_ASSERT(p, MA_OWNED);
663 
664 	MAC_CHECK(proc_check_wait, cred, p);
665 
666 	return (error);
667 }
668