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