xref: /freebsd/sys/security/mac/mac_process.c (revision 15bc6b2bd8d8c56ad74e57675dde8501bc7f53e1)
1 /*-
2  * Copyright (c) 1999-2002, 2008 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_proc_vm_revoke_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 /*
164  * When a thread becomes an NFS server daemon, its credential may need to be
165  * updated to reflect this so that policies can recognize when file system
166  * operations originate from the network.
167  *
168  * At some point, it would be desirable if the credential used for each NFS
169  * RPC could be set based on the RPC context (i.e., source system, etc) to
170  * provide more fine-grained access control.
171  */
172 void
173 mac_cred_associate_nfsd(struct ucred *cred)
174 {
175 
176 	MAC_PERFORM(cred_associate_nfsd, cred);
177 }
178 
179 /*
180  * Initialize MAC label for the first kernel process, from which other kernel
181  * processes and threads are spawned.
182  */
183 void
184 mac_cred_create_swapper(struct ucred *cred)
185 {
186 
187 	MAC_PERFORM(cred_create_swapper, cred);
188 }
189 
190 /*
191  * Initialize MAC label for the first userland process, from which other
192  * userland processes and threads are spawned.
193  */
194 void
195 mac_cred_create_init(struct ucred *cred)
196 {
197 
198 	MAC_PERFORM(cred_create_init, cred);
199 }
200 
201 int
202 mac_cred_externalize_label(struct label *label, char *elements,
203     char *outbuf, size_t outbuflen)
204 {
205 	int error;
206 
207 	MAC_EXTERNALIZE(cred, label, elements, outbuf, outbuflen);
208 
209 	return (error);
210 }
211 
212 int
213 mac_cred_internalize_label(struct label *label, char *string)
214 {
215 	int error;
216 
217 	MAC_INTERNALIZE(cred, label, string);
218 
219 	return (error);
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_proc_vm_revoke(struct thread *td)
318 {
319 	struct ucred *cred;
320 
321 	PROC_LOCK(td->td_proc);
322 	cred = crhold(td->td_proc->p_ucred);
323 	PROC_UNLOCK(td->td_proc);
324 
325 	/* XXX freeze all other threads */
326 	mac_proc_vm_revoke_recurse(td, cred,
327 	    &td->td_proc->p_vmspace->vm_map);
328 	/* XXX allow other threads to continue */
329 
330 	crfree(cred);
331 }
332 
333 static __inline const char *
334 prot2str(vm_prot_t prot)
335 {
336 
337 	switch (prot & VM_PROT_ALL) {
338 	case VM_PROT_READ:
339 		return ("r--");
340 	case VM_PROT_READ | VM_PROT_WRITE:
341 		return ("rw-");
342 	case VM_PROT_READ | VM_PROT_EXECUTE:
343 		return ("r-x");
344 	case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
345 		return ("rwx");
346 	case VM_PROT_WRITE:
347 		return ("-w-");
348 	case VM_PROT_EXECUTE:
349 		return ("--x");
350 	case VM_PROT_WRITE | VM_PROT_EXECUTE:
351 		return ("-wx");
352 	default:
353 		return ("---");
354 	}
355 }
356 
357 static void
358 mac_proc_vm_revoke_recurse(struct thread *td, struct ucred *cred,
359     struct vm_map *map)
360 {
361 	struct vm_map_entry *vme;
362 	int vfslocked, result;
363 	vm_prot_t revokeperms;
364 	vm_object_t backing_object, object;
365 	vm_ooffset_t offset;
366 	struct vnode *vp;
367 	struct mount *mp;
368 
369 	if (!mac_mmap_revocation)
370 		return;
371 
372 	vm_map_lock_read(map);
373 	for (vme = map->header.next; vme != &map->header; vme = vme->next) {
374 		if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
375 			mac_proc_vm_revoke_recurse(td, cred,
376 			    vme->object.sub_map);
377 			continue;
378 		}
379 		/*
380 		 * Skip over entries that obviously are not shared.
381 		 */
382 		if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) ||
383 		    !vme->max_protection)
384 			continue;
385 		/*
386 		 * Drill down to the deepest backing object.
387 		 */
388 		offset = vme->offset;
389 		object = vme->object.vm_object;
390 		if (object == NULL)
391 			continue;
392 		VM_OBJECT_LOCK(object);
393 		while ((backing_object = object->backing_object) != NULL) {
394 			VM_OBJECT_LOCK(backing_object);
395 			offset += object->backing_object_offset;
396 			VM_OBJECT_UNLOCK(object);
397 			object = backing_object;
398 		}
399 		VM_OBJECT_UNLOCK(object);
400 		/*
401 		 * At the moment, vm_maps and objects aren't considered by
402 		 * the MAC system, so only things with backing by a normal
403 		 * object (read: vnodes) are checked.
404 		 */
405 		if (object->type != OBJT_VNODE)
406 			continue;
407 		vp = (struct vnode *)object->handle;
408 		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
409 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
410 		result = vme->max_protection;
411 		mac_vnode_check_mmap_downgrade(cred, vp, &result);
412 		VOP_UNLOCK(vp, 0);
413 		/*
414 		 * Find out what maximum protection we may be allowing now
415 		 * but a policy needs to get removed.
416 		 */
417 		revokeperms = vme->max_protection & ~result;
418 		if (!revokeperms) {
419 			VFS_UNLOCK_GIANT(vfslocked);
420 			continue;
421 		}
422 		printf("pid %ld: revoking %s perms from %#lx:%ld "
423 		    "(max %s/cur %s)\n", (long)td->td_proc->p_pid,
424 		    prot2str(revokeperms), (u_long)vme->start,
425 		    (long)(vme->end - vme->start),
426 		    prot2str(vme->max_protection), prot2str(vme->protection));
427 		vm_map_lock_upgrade(map);
428 		/*
429 		 * This is the really simple case: if a map has more
430 		 * max_protection than is allowed, but it's not being
431 		 * actually used (that is, the current protection is still
432 		 * allowed), we can just wipe it out and do nothing more.
433 		 */
434 		if ((vme->protection & revokeperms) == 0) {
435 			vme->max_protection -= revokeperms;
436 		} else {
437 			if (revokeperms & VM_PROT_WRITE) {
438 				/*
439 				 * In the more complicated case, flush out all
440 				 * pending changes to the object then turn it
441 				 * copy-on-write.
442 				 */
443 				vm_object_reference(object);
444 				(void) vn_start_write(vp, &mp, V_WAIT);
445 				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
446 				VM_OBJECT_LOCK(object);
447 				vm_object_page_clean(object,
448 				    OFF_TO_IDX(offset),
449 				    OFF_TO_IDX(offset + vme->end - vme->start +
450 					PAGE_MASK),
451 				    OBJPC_SYNC);
452 				VM_OBJECT_UNLOCK(object);
453 				VOP_UNLOCK(vp, 0);
454 				vn_finished_write(mp);
455 				vm_object_deallocate(object);
456 				/*
457 				 * Why bother if there's no read permissions
458 				 * anymore?  For the rest, we need to leave
459 				 * the write permissions on for COW, or
460 				 * remove them entirely if configured to.
461 				 */
462 				if (!mac_mmap_revocation_via_cow) {
463 					vme->max_protection &= ~VM_PROT_WRITE;
464 					vme->protection &= ~VM_PROT_WRITE;
465 				} if ((revokeperms & VM_PROT_READ) == 0)
466 					vme->eflags |= MAP_ENTRY_COW |
467 					    MAP_ENTRY_NEEDS_COPY;
468 			}
469 			if (revokeperms & VM_PROT_EXECUTE) {
470 				vme->max_protection &= ~VM_PROT_EXECUTE;
471 				vme->protection &= ~VM_PROT_EXECUTE;
472 			}
473 			if (revokeperms & VM_PROT_READ) {
474 				vme->max_protection = 0;
475 				vme->protection = 0;
476 			}
477 			pmap_protect(map->pmap, vme->start, vme->end,
478 			    vme->protection & ~revokeperms);
479 			vm_map_simplify_entry(map, vme);
480 		}
481 		vm_map_lock_downgrade(map);
482 		VFS_UNLOCK_GIANT(vfslocked);
483 	}
484 	vm_map_unlock_read(map);
485 }
486 
487 /*
488  * When the subject's label changes, it may require revocation of privilege
489  * to mapped objects.  This can't be done on-the-fly later with a unified
490  * buffer cache.
491  */
492 void
493 mac_cred_relabel(struct ucred *cred, struct label *newlabel)
494 {
495 
496 	MAC_PERFORM(cred_relabel, cred, newlabel);
497 }
498 
499 int
500 mac_cred_check_relabel(struct ucred *cred, struct label *newlabel)
501 {
502 	int error;
503 
504 	MAC_CHECK(cred_check_relabel, cred, newlabel);
505 
506 	return (error);
507 }
508 
509 int
510 mac_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
511 {
512 	int error;
513 
514 	MAC_CHECK(cred_check_visible, cr1, cr2);
515 
516 	return (error);
517 }
518 
519 int
520 mac_proc_check_debug(struct ucred *cred, struct proc *p)
521 {
522 	int error;
523 
524 	PROC_LOCK_ASSERT(p, MA_OWNED);
525 
526 	MAC_CHECK(proc_check_debug, cred, p);
527 
528 	return (error);
529 }
530 
531 int
532 mac_proc_check_sched(struct ucred *cred, struct proc *p)
533 {
534 	int error;
535 
536 	PROC_LOCK_ASSERT(p, MA_OWNED);
537 
538 	MAC_CHECK(proc_check_sched, cred, p);
539 
540 	return (error);
541 }
542 
543 int
544 mac_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
545 {
546 	int error;
547 
548 	PROC_LOCK_ASSERT(p, MA_OWNED);
549 
550 	MAC_CHECK(proc_check_signal, cred, p, signum);
551 
552 	return (error);
553 }
554 
555 int
556 mac_proc_check_setuid(struct proc *p, struct ucred *cred, uid_t uid)
557 {
558 	int error;
559 
560 	PROC_LOCK_ASSERT(p, MA_OWNED);
561 
562 	MAC_CHECK(proc_check_setuid, cred, uid);
563 	return (error);
564 }
565 
566 int
567 mac_proc_check_seteuid(struct proc *p, struct ucred *cred, uid_t euid)
568 {
569 	int error;
570 
571 	PROC_LOCK_ASSERT(p, MA_OWNED);
572 
573 	MAC_CHECK(proc_check_seteuid, cred, euid);
574 	return (error);
575 }
576 
577 int
578 mac_proc_check_setgid(struct proc *p, struct ucred *cred, gid_t gid)
579 {
580 	int error;
581 
582 	PROC_LOCK_ASSERT(p, MA_OWNED);
583 
584 	MAC_CHECK(proc_check_setgid, cred, gid);
585 
586 	return (error);
587 }
588 
589 int
590 mac_proc_check_setegid(struct proc *p, struct ucred *cred, gid_t egid)
591 {
592 	int error;
593 
594 	PROC_LOCK_ASSERT(p, MA_OWNED);
595 
596 	MAC_CHECK(proc_check_setegid, cred, egid);
597 
598 	return (error);
599 }
600 
601 int
602 mac_proc_check_setgroups(struct proc *p, struct ucred *cred, int ngroups,
603     gid_t *gidset)
604 {
605 	int error;
606 
607 	PROC_LOCK_ASSERT(p, MA_OWNED);
608 
609 	MAC_CHECK(proc_check_setgroups, cred, ngroups, gidset);
610 	return (error);
611 }
612 
613 int
614 mac_proc_check_setreuid(struct proc *p, struct ucred *cred, uid_t ruid,
615     uid_t euid)
616 {
617 	int error;
618 
619 	PROC_LOCK_ASSERT(p, MA_OWNED);
620 
621 	MAC_CHECK(proc_check_setreuid, cred, ruid, euid);
622 
623 	return (error);
624 }
625 
626 int
627 mac_proc_check_setregid(struct proc *proc, struct ucred *cred, gid_t rgid,
628     gid_t egid)
629 {
630 	int error;
631 
632 	PROC_LOCK_ASSERT(proc, MA_OWNED);
633 
634 	MAC_CHECK(proc_check_setregid, cred, rgid, egid);
635 
636 	return (error);
637 }
638 
639 int
640 mac_proc_check_setresuid(struct proc *p, struct ucred *cred, uid_t ruid,
641     uid_t euid, uid_t suid)
642 {
643 	int error;
644 
645 	PROC_LOCK_ASSERT(p, MA_OWNED);
646 
647 	MAC_CHECK(proc_check_setresuid, cred, ruid, euid, suid);
648 	return (error);
649 }
650 
651 int
652 mac_proc_check_setresgid(struct proc *p, struct ucred *cred, gid_t rgid,
653     gid_t egid, gid_t sgid)
654 {
655 	int error;
656 
657 	PROC_LOCK_ASSERT(p, MA_OWNED);
658 
659 	MAC_CHECK(proc_check_setresgid, cred, rgid, egid, sgid);
660 
661 	return (error);
662 }
663 
664 int
665 mac_proc_check_wait(struct ucred *cred, struct proc *p)
666 {
667 	int error;
668 
669 	PROC_LOCK_ASSERT(p, MA_OWNED);
670 
671 	MAC_CHECK(proc_check_wait, cred, p);
672 
673 	return (error);
674 }
675