]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/security/mac/mac_process.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / sys / security / mac / mac_process.c
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 }