]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_mac.c
Close some races between procfs/ptrace and exit(2):
[FreeBSD/FreeBSD.git] / sys / kern / kern_mac.c
1 /*-
2  * Copyright (c) 1999-2002 Robert N. M. Watson
3  * Copyright (c) 2001 Ilmar S. Habibulin
4  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5  * Copyright (c) 2005 SPARTA, Inc.
6  * All rights reserved.
7  *
8  * This software was developed by Robert Watson and Ilmar Habibulin for the
9  * TrustedBSD Project.
10  *
11  * This software was developed for the FreeBSD Project in part by Network
12  * Associates Laboratories, the Security Research Division of Network
13  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
14  * as part of the DARPA CHATS research program.
15  *
16  * This software was enhanced by SPARTA ISSO under SPAWAR contract 
17  * N66001-04-C-6019 ("SEFOS").
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  */
40
41 /*-
42  * Framework for extensible kernel access control.  This file contains
43  * Kernel and userland interface to the framework, policy registration
44  * and composition.  Per-object interfaces, controls, and labeling may be
45  * found in src/sys/security/mac/.  Sample policies may be found in
46  * src/sys/security/mac_*.
47  */
48
49 #include <sys/cdefs.h>
50 __FBSDID("$FreeBSD$");
51
52 #include "opt_mac.h"
53 #include "opt_devfs.h"
54
55 #include <sys/param.h>
56 #include <sys/condvar.h>
57 #include <sys/extattr.h>
58 #include <sys/imgact.h>
59 #include <sys/kernel.h>
60 #include <sys/lock.h>
61 #include <sys/malloc.h>
62 #include <sys/mutex.h>
63 #include <sys/mac.h>
64 #include <sys/module.h>
65 #include <sys/proc.h>
66 #include <sys/sbuf.h>
67 #include <sys/systm.h>
68 #include <sys/sysproto.h>
69 #include <sys/sysent.h>
70 #include <sys/vnode.h>
71 #include <sys/mount.h>
72 #include <sys/file.h>
73 #include <sys/namei.h>
74 #include <sys/socket.h>
75 #include <sys/pipe.h>
76 #include <sys/socketvar.h>
77 #include <sys/sysctl.h>
78
79 #include <vm/vm.h>
80 #include <vm/pmap.h>
81 #include <vm/vm_map.h>
82 #include <vm/vm_object.h>
83
84 #include <sys/mac_policy.h>
85
86 #include <fs/devfs/devfs.h>
87
88 #include <net/bpfdesc.h>
89 #include <net/if.h>
90 #include <net/if_var.h>
91
92 #include <netinet/in.h>
93 #include <netinet/ip_var.h>
94
95 #include <security/mac/mac_internal.h>
96
97 #ifdef MAC
98
99 /*
100  * Declare that the kernel provides MAC support, version 1.  This permits
101  * modules to refuse to be loaded if the necessary support isn't present,
102  * even if it's pre-boot.
103  */
104 MODULE_VERSION(kernel_mac_support, 3);
105
106 SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
107     "TrustedBSD MAC policy controls");
108
109 #if MAC_MAX_SLOTS > 32
110 #error "MAC_MAX_SLOTS too large"
111 #endif
112
113 static unsigned int mac_max_slots = MAC_MAX_SLOTS;
114 static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
115 SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD,
116     &mac_max_slots, 0, "");
117
118 /*
119  * Has the kernel started generating labeled objects yet?  All read/write
120  * access to this variable is serialized during the boot process.  Following
121  * the end of serialization, we don't update this flag; no locking.
122  */
123 int     mac_late = 0;
124
125 /*
126  * Flag to indicate whether or not we should allocate label storage for
127  * new mbufs.  Since most dynamic policies we currently work with don't
128  * rely on mbuf labeling, try to avoid paying the cost of mtag allocation
129  * unless specifically notified of interest.  One result of this is
130  * that if a dynamically loaded policy requests mbuf labels, it must
131  * be able to deal with a NULL label being returned on any mbufs that
132  * were already in flight when the policy was loaded.  Since the policy
133  * already has to deal with uninitialized labels, this probably won't
134  * be a problem.  Note: currently no locking.  Will this be a problem?
135  */
136 #ifndef MAC_ALWAYS_LABEL_MBUF
137 int     mac_labelmbufs = 0;
138 #endif
139
140 #ifdef MAC_DEBUG
141 SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0,
142     "TrustedBSD MAC debug info");
143 SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0,
144     "TrustedBSD MAC object counters");
145
146 static unsigned int nmactemp;
147 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD,
148     &nmactemp, 0, "number of temporary labels in use");
149 #endif
150
151 static int      mac_policy_register(struct mac_policy_conf *mpc);
152 static int      mac_policy_unregister(struct mac_policy_conf *mpc);
153
154 MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
155
156 /*
157  * mac_static_policy_list holds a list of policy modules that are not
158  * loaded while the system is "live", and cannot be unloaded.  These
159  * policies can be invoked without holding the busy count.
160  *
161  * mac_policy_list stores the list of dynamic policies.  A busy count is
162  * maintained for the list, stored in mac_policy_busy.  The busy count
163  * is protected by mac_policy_mtx; the list may be modified only
164  * while the busy count is 0, requiring that the lock be held to
165  * prevent new references to the list from being acquired.  For almost
166  * all operations, incrementing the busy count is sufficient to
167  * guarantee consistency, as the list cannot be modified while the
168  * busy count is elevated.  For a few special operations involving a
169  * change to the list of active policies, the mtx itself must be held.
170  * A condition variable, mac_policy_cv, is used to signal potential
171  * exclusive consumers that they should try to acquire the lock if a
172  * first attempt at exclusive access fails.
173  */
174 #ifndef MAC_STATIC
175 static struct mtx mac_policy_mtx;
176 static struct cv mac_policy_cv;
177 static int mac_policy_count;
178 #endif
179 struct mac_policy_list_head mac_policy_list;
180 struct mac_policy_list_head mac_static_policy_list;
181
182 /*
183  * We manually invoke WITNESS_WARN() to allow Witness to generate
184  * warnings even if we don't end up ever triggering the wait at
185  * run-time.  The consumer of the exclusive interface must not hold
186  * any locks (other than potentially Giant) since we may sleep for
187  * long (potentially indefinite) periods of time waiting for the
188  * framework to become quiescent so that a policy list change may
189  * be made.
190  */
191 void
192 mac_policy_grab_exclusive(void)
193 {
194
195 #ifndef MAC_STATIC
196         if (!mac_late)
197                 return;
198
199         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
200             "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
201         mtx_lock(&mac_policy_mtx);
202         while (mac_policy_count != 0)
203                 cv_wait(&mac_policy_cv, &mac_policy_mtx);
204 #endif
205 }
206
207 void
208 mac_policy_assert_exclusive(void)
209 {
210
211 #ifndef MAC_STATIC
212         if (!mac_late)
213                 return;
214
215         mtx_assert(&mac_policy_mtx, MA_OWNED);
216         KASSERT(mac_policy_count == 0,
217             ("mac_policy_assert_exclusive(): not exclusive"));
218 #endif
219 }
220
221 void
222 mac_policy_release_exclusive(void)
223 {
224
225 #ifndef MAC_STATIC
226         if (!mac_late)
227                 return;
228
229         KASSERT(mac_policy_count == 0,
230             ("mac_policy_release_exclusive(): not exclusive"));
231         mtx_unlock(&mac_policy_mtx);
232         cv_signal(&mac_policy_cv);
233 #endif
234 }
235
236 void
237 mac_policy_list_busy(void)
238 {
239
240 #ifndef MAC_STATIC
241         if (!mac_late)
242                 return;
243
244         mtx_lock(&mac_policy_mtx);
245         mac_policy_count++;
246         mtx_unlock(&mac_policy_mtx);
247 #endif
248 }
249
250 int
251 mac_policy_list_conditional_busy(void)
252 {
253 #ifndef MAC_STATIC
254         int ret;
255
256         if (!mac_late)
257                 return (1);
258
259         mtx_lock(&mac_policy_mtx);
260         if (!LIST_EMPTY(&mac_policy_list)) {
261                 mac_policy_count++;
262                 ret = 1;
263         } else
264                 ret = 0;
265         mtx_unlock(&mac_policy_mtx);
266         return (ret);
267 #else
268         if (!mac_late)
269                 return (1);
270
271         return (1);
272 #endif
273 }
274
275 void
276 mac_policy_list_unbusy(void)
277 {
278
279 #ifndef MAC_STATIC
280         if (!mac_late)
281                 return;
282
283         mtx_lock(&mac_policy_mtx);
284         mac_policy_count--;
285         KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
286         if (mac_policy_count == 0)
287                 cv_signal(&mac_policy_cv);
288         mtx_unlock(&mac_policy_mtx);
289 #endif
290 }
291
292 /*
293  * Initialize the MAC subsystem, including appropriate SMP locks.
294  */
295 static void
296 mac_init(void)
297 {
298
299         LIST_INIT(&mac_static_policy_list);
300         LIST_INIT(&mac_policy_list);
301         mac_labelzone_init();
302
303 #ifndef MAC_STATIC
304         mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
305         cv_init(&mac_policy_cv, "mac_policy_cv");
306 #endif
307 }
308
309 /*
310  * For the purposes of modules that want to know if they were loaded
311  * "early", set the mac_late flag once we've processed modules either
312  * linked into the kernel, or loaded before the kernel startup.
313  */
314 static void
315 mac_late_init(void)
316 {
317
318         mac_late = 1;
319 }
320
321 /*
322  * After the policy list has changed, walk the list to update any global
323  * flags.  Currently, we support only one flag, and it's conditionally
324  * defined; as a result, the entire function is conditional.  Eventually,
325  * the #else case might also iterate across the policies.
326  */
327 static void
328 mac_policy_updateflags(void)
329 {
330 #ifndef MAC_ALWAYS_LABEL_MBUF
331         struct mac_policy_conf *tmpc;
332         int labelmbufs;
333
334         mac_policy_assert_exclusive();
335
336         labelmbufs = 0;
337         LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
338                 if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
339                         labelmbufs++;
340         }
341         LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
342                 if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
343                         labelmbufs++;
344         }
345         mac_labelmbufs = (labelmbufs != 0);
346 #endif
347 }
348
349 /*
350  * Allow MAC policy modules to register during boot, etc.
351  */
352 int
353 mac_policy_modevent(module_t mod, int type, void *data)
354 {
355         struct mac_policy_conf *mpc;
356         int error;
357
358         error = 0;
359         mpc = (struct mac_policy_conf *) data;
360
361 #ifdef MAC_STATIC
362         if (mac_late) {
363                 printf("mac_policy_modevent: MAC_STATIC and late\n");
364                 return (EBUSY);
365         }
366 #endif
367
368         switch (type) {
369         case MOD_LOAD:
370                 if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
371                     mac_late) {
372                         printf("mac_policy_modevent: can't load %s policy "
373                             "after booting\n", mpc->mpc_name);
374                         error = EBUSY;
375                         break;
376                 }
377                 error = mac_policy_register(mpc);
378                 break;
379         case MOD_UNLOAD:
380                 /* Don't unregister the module if it was never registered. */
381                 if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
382                     != 0)
383                         error = mac_policy_unregister(mpc);
384                 else
385                         error = 0;
386                 break;
387         default:
388                 error = EOPNOTSUPP;
389                 break;
390         }
391
392         return (error);
393 }
394
395 static int
396 mac_policy_register(struct mac_policy_conf *mpc)
397 {
398         struct mac_policy_conf *tmpc;
399         int error, slot, static_entry;
400
401         error = 0;
402
403         /*
404          * We don't technically need exclusive access while !mac_late,
405          * but hold it for assertion consistency.
406          */
407         mac_policy_grab_exclusive();
408
409         /*
410          * If the module can potentially be unloaded, or we're loading
411          * late, we have to stick it in the non-static list and pay
412          * an extra performance overhead.  Otherwise, we can pay a
413          * light locking cost and stick it in the static list.
414          */
415         static_entry = (!mac_late &&
416             !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
417
418         if (static_entry) {
419                 LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
420                         if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
421                                 error = EEXIST;
422                                 goto out;
423                         }
424                 }
425         } else {
426                 LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
427                         if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
428                                 error = EEXIST;
429                                 goto out;
430                         }
431                 }
432         }
433         if (mpc->mpc_field_off != NULL) {
434                 slot = ffs(mac_slot_offsets_free);
435                 if (slot == 0) {
436                         error = ENOMEM;
437                         goto out;
438                 }
439                 slot--;
440                 mac_slot_offsets_free &= ~(1 << slot);
441                 *mpc->mpc_field_off = slot;
442         }
443         mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
444
445         /*
446          * If we're loading a MAC module after the framework has
447          * initialized, it has to go into the dynamic list.  If
448          * we're loading it before we've finished initializing,
449          * it can go into the static list with weaker locker
450          * requirements.
451          */
452         if (static_entry)
453                 LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
454         else
455                 LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
456
457         /* Per-policy initialization. */
458         if (mpc->mpc_ops->mpo_init != NULL)
459                 (*(mpc->mpc_ops->mpo_init))(mpc);
460         mac_policy_updateflags();
461
462         printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
463             mpc->mpc_name);
464
465 out:
466         mac_policy_release_exclusive();
467         return (error);
468 }
469
470 static int
471 mac_policy_unregister(struct mac_policy_conf *mpc)
472 {
473
474         /*
475          * If we fail the load, we may get a request to unload.  Check
476          * to see if we did the run-time registration, and if not,
477          * silently succeed.
478          */
479         mac_policy_grab_exclusive();
480         if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
481                 mac_policy_release_exclusive();
482                 return (0);
483         }
484 #if 0
485         /*
486          * Don't allow unloading modules with private data.
487          */
488         if (mpc->mpc_field_off != NULL) {
489                 MAC_POLICY_LIST_UNLOCK();
490                 return (EBUSY);
491         }
492 #endif
493         /*
494          * Only allow the unload to proceed if the module is unloadable
495          * by its own definition.
496          */
497         if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
498                 mac_policy_release_exclusive();
499                 return (EBUSY);
500         }
501         if (mpc->mpc_ops->mpo_destroy != NULL)
502                 (*(mpc->mpc_ops->mpo_destroy))(mpc);
503
504         LIST_REMOVE(mpc, mpc_list);
505         mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
506         mac_policy_updateflags();
507
508         mac_policy_release_exclusive();
509
510         printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
511             mpc->mpc_name);
512
513         return (0);
514 }
515
516 /*
517  * Define an error value precedence, and given two arguments, selects the
518  * value with the higher precedence.
519  */
520 int
521 mac_error_select(int error1, int error2)
522 {
523
524         /* Certain decision-making errors take top priority. */
525         if (error1 == EDEADLK || error2 == EDEADLK)
526                 return (EDEADLK);
527
528         /* Invalid arguments should be reported where possible. */
529         if (error1 == EINVAL || error2 == EINVAL)
530                 return (EINVAL);
531
532         /* Precedence goes to "visibility", with both process and file. */
533         if (error1 == ESRCH || error2 == ESRCH)
534                 return (ESRCH);
535
536         if (error1 == ENOENT || error2 == ENOENT)
537                 return (ENOENT);
538
539         /* Precedence goes to DAC/MAC protections. */
540         if (error1 == EACCES || error2 == EACCES)
541                 return (EACCES);
542
543         /* Precedence goes to privilege. */
544         if (error1 == EPERM || error2 == EPERM)
545                 return (EPERM);
546
547         /* Precedence goes to error over success; otherwise, arbitrary. */
548         if (error1 != 0)
549                 return (error1);
550         return (error2);
551 }
552
553 void
554 mac_init_label(struct label *label)
555 {
556
557         bzero(label, sizeof(*label));
558         label->l_flags = MAC_FLAG_INITIALIZED;
559 }
560
561 void
562 mac_destroy_label(struct label *label)
563 {
564
565         KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
566             ("destroying uninitialized label"));
567
568         bzero(label, sizeof(*label));
569         /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
570 }
571
572 int
573 mac_check_structmac_consistent(struct mac *mac)
574 {
575
576         if (mac->m_buflen < 0 ||
577             mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
578                 return (EINVAL);
579
580         return (0);
581 }
582
583 /*
584  * MPSAFE
585  */
586 int
587 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
588 {
589         char *elements, *buffer;
590         struct mac mac;
591         struct proc *tproc;
592         struct ucred *tcred;
593         int error;
594
595         error = copyin(uap->mac_p, &mac, sizeof(mac));
596         if (error)
597                 return (error);
598
599         error = mac_check_structmac_consistent(&mac);
600         if (error)
601                 return (error);
602
603         tproc = pfind(uap->pid);
604         if (tproc == NULL)
605                 return (ESRCH);
606
607         tcred = NULL;                           /* Satisfy gcc. */
608         error = p_cansee(td, tproc);
609         if (error == 0)
610                 tcred = crhold(tproc->p_ucred);
611         PROC_UNLOCK(tproc);
612         if (error)
613                 return (error);
614
615         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
616         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
617         if (error) {
618                 free(elements, M_MACTEMP);
619                 crfree(tcred);
620                 return (error);
621         }
622
623         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
624         error = mac_externalize_cred_label(tcred->cr_label, elements,
625             buffer, mac.m_buflen);
626         if (error == 0)
627                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
628
629         free(buffer, M_MACTEMP);
630         free(elements, M_MACTEMP);
631         crfree(tcred);
632         return (error);
633 }
634
635 /*
636  * MPSAFE
637  */
638 int
639 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
640 {
641         char *elements, *buffer;
642         struct mac mac;
643         int error;
644
645         error = copyin(uap->mac_p, &mac, sizeof(mac));
646         if (error)
647                 return (error);
648
649         error = mac_check_structmac_consistent(&mac);
650         if (error)
651                 return (error);
652
653         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
654         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
655         if (error) {
656                 free(elements, M_MACTEMP);
657                 return (error);
658         }
659
660         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
661         error = mac_externalize_cred_label(td->td_ucred->cr_label,
662             elements, buffer, mac.m_buflen);
663         if (error == 0)
664                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
665
666         free(buffer, M_MACTEMP);
667         free(elements, M_MACTEMP);
668         return (error);
669 }
670
671 /*
672  * MPSAFE
673  */
674 int
675 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
676 {
677         struct ucred *newcred, *oldcred;
678         struct label *intlabel;
679         struct proc *p;
680         struct mac mac;
681         char *buffer;
682         int error;
683
684         error = copyin(uap->mac_p, &mac, sizeof(mac));
685         if (error)
686                 return (error);
687
688         error = mac_check_structmac_consistent(&mac);
689         if (error)
690                 return (error);
691
692         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
693         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
694         if (error) {
695                 free(buffer, M_MACTEMP);
696                 return (error);
697         }
698
699         intlabel = mac_cred_label_alloc();
700         error = mac_internalize_cred_label(intlabel, buffer);
701         free(buffer, M_MACTEMP);
702         if (error)
703                 goto out;
704
705         newcred = crget();
706
707         p = td->td_proc;
708         PROC_LOCK(p);
709         oldcred = p->p_ucred;
710
711         error = mac_check_cred_relabel(oldcred, intlabel);
712         if (error) {
713                 PROC_UNLOCK(p);
714                 crfree(newcred);
715                 goto out;
716         }
717
718         setsugid(p);
719         crcopy(newcred, oldcred);
720         mac_relabel_cred(newcred, intlabel);
721         p->p_ucred = newcred;
722
723         /*
724          * Grab additional reference for use while revoking mmaps, prior
725          * to releasing the proc lock and sharing the cred.
726          */
727         crhold(newcred);
728         PROC_UNLOCK(p);
729
730         if (mac_enforce_vm) {
731                 mac_cred_mmapped_drop_perms(td, newcred);
732         }
733
734         crfree(newcred);        /* Free revocation reference. */
735         crfree(oldcred);
736
737 out:
738         mac_cred_label_free(intlabel);
739         return (error);
740 }
741
742 /*
743  * MPSAFE
744  */
745 int
746 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
747 {
748         char *elements, *buffer;
749         struct label *intlabel;
750         struct file *fp;
751         struct mac mac;
752         struct vnode *vp;
753         struct pipe *pipe;
754         struct socket *so;
755         short label_type;
756         int vfslocked, error;
757
758         error = copyin(uap->mac_p, &mac, sizeof(mac));
759         if (error)
760                 return (error);
761
762         error = mac_check_structmac_consistent(&mac);
763         if (error)
764                 return (error);
765
766         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
767         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
768         if (error) {
769                 free(elements, M_MACTEMP);
770                 return (error);
771         }
772
773         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
774         error = fget(td, uap->fd, &fp);
775         if (error)
776                 goto out;
777
778         label_type = fp->f_type;
779         switch (fp->f_type) {
780         case DTYPE_FIFO:
781         case DTYPE_VNODE:
782                 vp = fp->f_vnode;
783                 intlabel = mac_vnode_label_alloc();
784                 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
785                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
786                 mac_copy_vnode_label(vp->v_label, intlabel);
787                 VOP_UNLOCK(vp, 0, td);
788                 VFS_UNLOCK_GIANT(vfslocked);
789                 error = mac_externalize_vnode_label(intlabel, elements,
790                     buffer, mac.m_buflen);
791                 mac_vnode_label_free(intlabel);
792                 break;
793
794         case DTYPE_PIPE:
795                 pipe = fp->f_data;
796                 intlabel = mac_pipe_label_alloc();
797                 PIPE_LOCK(pipe);
798                 mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel);
799                 PIPE_UNLOCK(pipe);
800                 error = mac_externalize_pipe_label(intlabel, elements,
801                     buffer, mac.m_buflen);
802                 mac_pipe_label_free(intlabel);
803                 break;
804
805         case DTYPE_SOCKET:
806                 so = fp->f_data;
807                 intlabel = mac_socket_label_alloc(M_WAITOK);
808                 NET_LOCK_GIANT();
809                 SOCK_LOCK(so);
810                 mac_copy_socket_label(so->so_label, intlabel);
811                 SOCK_UNLOCK(so);
812                 NET_UNLOCK_GIANT();
813                 error = mac_externalize_socket_label(intlabel, elements,
814                     buffer, mac.m_buflen);
815                 mac_socket_label_free(intlabel);
816                 break;
817
818         default:
819                 error = EINVAL;
820         }
821         fdrop(fp, td);
822         if (error == 0)
823                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
824
825 out:
826         free(buffer, M_MACTEMP);
827         free(elements, M_MACTEMP);
828         return (error);
829 }
830
831 /*
832  * MPSAFE
833  */
834 int
835 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
836 {
837         char *elements, *buffer;
838         struct nameidata nd;
839         struct label *intlabel;
840         struct mac mac;
841         int vfslocked, error;
842
843         error = copyin(uap->mac_p, &mac, sizeof(mac));
844         if (error)
845                 return (error);
846
847         error = mac_check_structmac_consistent(&mac);
848         if (error)
849                 return (error);
850
851         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
852         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
853         if (error) {
854                 free(elements, M_MACTEMP);
855                 return (error);
856         }
857
858         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
859         NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
860             uap->path_p, td);
861         error = namei(&nd);
862         if (error)
863                 goto out;
864
865         intlabel = mac_vnode_label_alloc();
866         vfslocked = NDHASGIANT(&nd);
867         mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
868         error = mac_externalize_vnode_label(intlabel, elements, buffer,
869             mac.m_buflen);
870
871         NDFREE(&nd, 0);
872         VFS_UNLOCK_GIANT(vfslocked);
873         mac_vnode_label_free(intlabel);
874         if (error == 0)
875                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
876
877 out:
878         free(buffer, M_MACTEMP);
879         free(elements, M_MACTEMP);
880
881         return (error);
882 }
883
884 /*
885  * MPSAFE
886  */
887 int
888 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
889 {
890         char *elements, *buffer;
891         struct nameidata nd;
892         struct label *intlabel;
893         struct mac mac;
894         int vfslocked, error;
895
896         error = copyin(uap->mac_p, &mac, sizeof(mac));
897         if (error)
898                 return (error);
899
900         error = mac_check_structmac_consistent(&mac);
901         if (error)
902                 return (error);
903
904         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
905         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
906         if (error) {
907                 free(elements, M_MACTEMP);
908                 return (error);
909         }
910
911         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
912         NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
913             uap->path_p, td);
914         error = namei(&nd);
915         if (error)
916                 goto out;
917
918         intlabel = mac_vnode_label_alloc();
919         vfslocked = NDHASGIANT(&nd);
920         mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
921         error = mac_externalize_vnode_label(intlabel, elements, buffer,
922             mac.m_buflen);
923         NDFREE(&nd, 0);
924         VFS_UNLOCK_GIANT(vfslocked);
925         mac_vnode_label_free(intlabel);
926
927         if (error == 0)
928                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
929
930 out:
931         free(buffer, M_MACTEMP);
932         free(elements, M_MACTEMP);
933
934         return (error);
935 }
936
937 /*
938  * MPSAFE
939  */
940 int
941 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
942 {
943         struct label *intlabel;
944         struct pipe *pipe;
945         struct socket *so;
946         struct file *fp;
947         struct mount *mp;
948         struct vnode *vp;
949         struct mac mac;
950         char *buffer;
951         int error, vfslocked;
952
953         error = copyin(uap->mac_p, &mac, sizeof(mac));
954         if (error)
955                 return (error);
956
957         error = mac_check_structmac_consistent(&mac);
958         if (error)
959                 return (error);
960
961         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
962         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
963         if (error) {
964                 free(buffer, M_MACTEMP);
965                 return (error);
966         }
967
968         error = fget(td, uap->fd, &fp);
969         if (error)
970                 goto out;
971
972         switch (fp->f_type) {
973         case DTYPE_FIFO:
974         case DTYPE_VNODE:
975                 intlabel = mac_vnode_label_alloc();
976                 error = mac_internalize_vnode_label(intlabel, buffer);
977                 if (error) {
978                         mac_vnode_label_free(intlabel);
979                         break;
980                 }
981                 vp = fp->f_vnode;
982                 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
983                 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
984                 if (error != 0) {
985                         VFS_UNLOCK_GIANT(vfslocked);
986                         mac_vnode_label_free(intlabel);
987                         break;
988                 }
989                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
990                 error = vn_setlabel(vp, intlabel, td->td_ucred);
991                 VOP_UNLOCK(vp, 0, td);
992                 vn_finished_write(mp);
993                 VFS_UNLOCK_GIANT(vfslocked);
994                 mac_vnode_label_free(intlabel);
995                 break;
996
997         case DTYPE_PIPE:
998                 intlabel = mac_pipe_label_alloc();
999                 error = mac_internalize_pipe_label(intlabel, buffer);
1000                 if (error == 0) {
1001                         pipe = fp->f_data;
1002                         PIPE_LOCK(pipe);
1003                         error = mac_pipe_label_set(td->td_ucred,
1004                             pipe->pipe_pair, intlabel);
1005                         PIPE_UNLOCK(pipe);
1006                 }
1007                 mac_pipe_label_free(intlabel);
1008                 break;
1009
1010         case DTYPE_SOCKET:
1011                 intlabel = mac_socket_label_alloc(M_WAITOK);
1012                 error = mac_internalize_socket_label(intlabel, buffer);
1013                 if (error == 0) {
1014                         so = fp->f_data;
1015                         NET_LOCK_GIANT();
1016                         error = mac_socket_label_set(td->td_ucred, so,
1017                             intlabel);
1018                         NET_UNLOCK_GIANT();
1019                 }
1020                 mac_socket_label_free(intlabel);
1021                 break;
1022
1023         default:
1024                 error = EINVAL;
1025         }
1026         fdrop(fp, td);
1027 out:
1028         free(buffer, M_MACTEMP);
1029         return (error);
1030 }
1031
1032 /*
1033  * MPSAFE
1034  */
1035 int
1036 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1037 {
1038         struct label *intlabel;
1039         struct nameidata nd;
1040         struct mount *mp;
1041         struct mac mac;
1042         char *buffer;
1043         int vfslocked, error;
1044
1045         error = copyin(uap->mac_p, &mac, sizeof(mac));
1046         if (error)
1047                 return (error);
1048
1049         error = mac_check_structmac_consistent(&mac);
1050         if (error)
1051                 return (error);
1052
1053         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1054         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1055         if (error) {
1056                 free(buffer, M_MACTEMP);
1057                 return (error);
1058         }
1059
1060         intlabel = mac_vnode_label_alloc();
1061         error = mac_internalize_vnode_label(intlabel, buffer);
1062         free(buffer, M_MACTEMP);
1063         if (error)
1064                 goto out;
1065
1066         NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
1067             uap->path_p, td);
1068         error = namei(&nd);
1069         vfslocked = NDHASGIANT(&nd);
1070         if (error == 0) {
1071                 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1072                 if (error == 0)
1073                         error = vn_setlabel(nd.ni_vp, intlabel,
1074                             td->td_ucred);
1075                 vn_finished_write(mp);
1076         }
1077
1078         NDFREE(&nd, 0);
1079         VFS_UNLOCK_GIANT(vfslocked);
1080 out:
1081         mac_vnode_label_free(intlabel);
1082         return (error);
1083 }
1084
1085 /*
1086  * MPSAFE
1087  */
1088 int
1089 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1090 {
1091         struct label *intlabel;
1092         struct nameidata nd;
1093         struct mount *mp;
1094         struct mac mac;
1095         char *buffer;
1096         int vfslocked, error;
1097
1098         error = copyin(uap->mac_p, &mac, sizeof(mac));
1099         if (error)
1100                 return (error);
1101
1102         error = mac_check_structmac_consistent(&mac);
1103         if (error)
1104                 return (error);
1105
1106         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1107         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1108         if (error) {
1109                 free(buffer, M_MACTEMP);
1110                 return (error);
1111         }
1112
1113         intlabel = mac_vnode_label_alloc();
1114         error = mac_internalize_vnode_label(intlabel, buffer);
1115         free(buffer, M_MACTEMP);
1116         if (error)
1117                 goto out;
1118
1119         NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
1120             uap->path_p, td);
1121         error = namei(&nd);
1122         vfslocked = NDHASGIANT(&nd);
1123         if (error == 0) {
1124                 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1125                 if (error == 0)
1126                         error = vn_setlabel(nd.ni_vp, intlabel,
1127                             td->td_ucred);
1128                 vn_finished_write(mp);
1129         }
1130
1131         NDFREE(&nd, 0);
1132         VFS_UNLOCK_GIANT(vfslocked);
1133 out:
1134         mac_vnode_label_free(intlabel);
1135         return (error);
1136 }
1137
1138 /*
1139  * MPSAFE
1140  */
1141 int
1142 mac_syscall(struct thread *td, struct mac_syscall_args *uap)
1143 {
1144         struct mac_policy_conf *mpc;
1145         char target[MAC_MAX_POLICY_NAME];
1146         int entrycount, error;
1147
1148         error = copyinstr(uap->policy, target, sizeof(target), NULL);
1149         if (error)
1150                 return (error);
1151
1152         error = ENOSYS;
1153         LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1154                 if (strcmp(mpc->mpc_name, target) == 0 &&
1155                     mpc->mpc_ops->mpo_syscall != NULL) {
1156                         error = mpc->mpc_ops->mpo_syscall(td,
1157                             uap->call, uap->arg);
1158                         goto out;
1159                 }
1160         }
1161
1162         if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1163                 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1164                         if (strcmp(mpc->mpc_name, target) == 0 &&
1165                             mpc->mpc_ops->mpo_syscall != NULL) {
1166                                 error = mpc->mpc_ops->mpo_syscall(td,
1167                                     uap->call, uap->arg);
1168                                 break;
1169                         }
1170                 }
1171                 mac_policy_list_unbusy();
1172         }
1173 out:
1174         return (error);
1175 }
1176
1177 SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1178 SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1179
1180 #else /* !MAC */
1181
1182 int
1183 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1184 {
1185
1186         return (ENOSYS);
1187 }
1188
1189 int
1190 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1191 {
1192
1193         return (ENOSYS);
1194 }
1195
1196 int
1197 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1198 {
1199
1200         return (ENOSYS);
1201 }
1202
1203 int
1204 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1205 {
1206
1207         return (ENOSYS);
1208 }
1209
1210 int
1211 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1212 {
1213
1214         return (ENOSYS);
1215 }
1216
1217 int
1218 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1219 {
1220
1221         return (ENOSYS);
1222 }
1223
1224 int
1225 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1226 {
1227
1228         return (ENOSYS);
1229 }
1230
1231 int
1232 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1233 {
1234
1235         return (ENOSYS);
1236 }
1237
1238 int
1239 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1240 {
1241
1242         return (ENOSYS);
1243 }
1244
1245 int
1246 mac_syscall(struct thread *td, struct mac_syscall_args *uap)
1247 {
1248
1249         return (ENOSYS);
1250 }
1251
1252 #endif /* !MAC */