xref: /freebsd/sys/security/mac/mac_syscalls.c (revision b1bebaaba9b9c0ddfe503c43ca8e9e3917ee2c57)
1 /*-
2  * Copyright (c) 1999-2002, 2006, 2009 Robert N. M. Watson
3  * Copyright (c) 2001 Ilmar S. Habibulin
4  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5  * Copyright (c) 2005-2006 SPARTA, Inc.
6  * Copyright (c) 2008 Apple 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  * This software was developed at the University of Cambridge Computer
21  * Laboratory with support from a grant from Google, Inc.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  */
44 
45 #include <sys/cdefs.h>
46 #include "opt_mac.h"
47 
48 #include <sys/param.h>
49 #include <sys/abi_compat.h>
50 #include <sys/capsicum.h>
51 #include <sys/fcntl.h>
52 #include <sys/jail.h>
53 #include <sys/jaildesc.h>
54 #include <sys/kernel.h>
55 #include <sys/lock.h>
56 #include <sys/malloc.h>
57 #include <sys/mutex.h>
58 #include <sys/mac.h>
59 #include <sys/proc.h>
60 #include <sys/systm.h>
61 #include <sys/sysctl.h>
62 #include <sys/sysent.h>
63 #include <sys/sysproto.h>
64 #include <sys/vnode.h>
65 #include <sys/mount.h>
66 #include <sys/file.h>
67 #include <sys/namei.h>
68 #include <sys/socket.h>
69 #include <sys/pipe.h>
70 #include <sys/socketvar.h>
71 
72 #include <security/mac/mac_framework.h>
73 #include <security/mac/mac_internal.h>
74 #include <security/mac/mac_policy.h>
75 #include <security/mac/mac_syscalls.h>
76 
77 #ifdef MAC
78 
79 FEATURE(security_mac, "Mandatory Access Control Framework support");
80 
81 static int	kern___mac_get_path(struct thread *td, const char *path_p,
82 		    struct mac *mac_p, int follow);
83 static int	kern___mac_set_path(struct thread *td, const char *path_p,
84 		    struct mac *mac_p, int follow);
85 
86 #ifdef COMPAT_FREEBSD32
87 struct mac32 {
88 	uint32_t	m_buflen;	/* size_t */
89 	uint32_t	m_string;	/* char * */
90 };
91 #endif
92 
93 static int
94 mac_label_copyin_string(struct mac *const mac, char **const u_string,
95     int flag)
96 {
97 	char *buffer;
98 	int error;
99 
100 	error = mac_check_structmac_consistent(mac);
101 	if (error != 0)
102 		return (error);
103 
104 	/* 'm_buflen' not too big checked by function call above. */
105 	buffer = malloc(mac->m_buflen, M_MACTEMP, flag);
106 	if (buffer == NULL)
107 		return (ENOMEM);
108 
109 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
110 	if (error != 0) {
111 		free(buffer, M_MACTEMP);
112 		return (error);
113 	}
114 
115 	MPASS(error == 0);
116 	if (u_string != NULL)
117 		*u_string = mac->m_string;
118 	mac->m_string = buffer;
119 	return (0);
120 }
121 
122 /*
123  * Copyin a 'struct mac', including the string pointed to by 'm_string'.
124  *
125  * On success (0 returned), fills '*mac', whose associated storage must be freed
126  * after use by calling free_copied_label() (which see).  On success, 'u_string'
127  * if not NULL is filled with the userspace address for 'u_mac->m_string'.
128  */
129 int
130 mac_label_copyin(const void *const u_mac, struct mac *const mac,
131     char **const u_string)
132 {
133 	int error;
134 
135 #ifdef COMPAT_FREEBSD32
136 	if (SV_CURPROC_FLAG(SV_ILP32)) {
137 		struct mac32 mac32;
138 
139 		error = copyin(u_mac, &mac32, sizeof(mac32));
140 		if (error != 0)
141 			return (error);
142 
143 		CP(mac32, *mac, m_buflen);
144 		PTRIN_CP(mac32, *mac, m_string);
145 	} else
146 #endif
147 	{
148 		error = copyin(u_mac, mac, sizeof(*mac));
149 		if (error != 0)
150 			return (error);
151 	}
152 
153 	return (mac_label_copyin_string(mac, u_string, M_WAITOK));
154 }
155 
156 void
157 free_copied_label(const struct mac *const mac)
158 {
159 	free(mac->m_string, M_MACTEMP);
160 }
161 
162 int
163 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
164 {
165 	char *buffer, *u_buffer;
166 	struct mac mac;
167 	struct proc *tproc;
168 	struct ucred *tcred;
169 	int error;
170 
171 	error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
172 	if (error)
173 		return (error);
174 
175 	tproc = pfind(uap->pid);
176 	if (tproc == NULL) {
177 		error = ESRCH;
178 		goto free_mac_and_exit;
179 	}
180 
181 	tcred = NULL;				/* Satisfy gcc. */
182 	error = p_cansee(td, tproc);
183 	if (error == 0)
184 		tcred = crhold(tproc->p_ucred);
185 	PROC_UNLOCK(tproc);
186 	if (error)
187 		goto free_mac_and_exit;
188 
189 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
190 	error = mac_cred_externalize_label(tcred->cr_label, mac.m_string,
191 	    buffer, mac.m_buflen);
192 	if (error == 0)
193 		error = copyout(buffer, u_buffer, strlen(buffer)+1);
194 	free(buffer, M_MACTEMP);
195 	crfree(tcred);
196 
197 free_mac_and_exit:
198 	free_copied_label(&mac);
199 	return (error);
200 }
201 
202 int
203 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
204 {
205 	char *buffer, *u_buffer;
206 	struct mac mac;
207 	int error;
208 
209 	error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
210 	if (error)
211 		return (error);
212 
213 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
214 	error = mac_cred_externalize_label(td->td_ucred->cr_label,
215 	    mac.m_string, buffer, mac.m_buflen);
216 	if (error == 0)
217 		error = copyout(buffer, u_buffer, strlen(buffer)+1);
218 
219 	free(buffer, M_MACTEMP);
220 	free_copied_label(&mac);
221 	return (error);
222 }
223 
224 /*
225  * Performs preparation (including allocations) for mac_set_proc().
226  *
227  * No lock should be held while calling this function.  On success,
228  * mac_set_proc_finish() must be called to free the data associated to
229  * 'mac_set_proc_data', even if mac_set_proc_core() fails.  'mac_set_proc_data'
230  * is not set in case of error, and is set to a non-NULL value on success.
231  */
232 int
233 mac_set_proc_prepare(struct thread *const td, const struct mac *const mac,
234     void **const mac_set_proc_data)
235 {
236 	struct label *intlabel;
237 	int error;
238 
239 	PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
240 
241 	if (!(mac_labeled & MPC_OBJECT_CRED))
242 		return (EINVAL);
243 
244 	intlabel = mac_cred_label_alloc();
245 	error = mac_cred_internalize_label(intlabel, mac->m_string);
246 	if (error) {
247 		mac_cred_label_free(intlabel);
248 		return (error);
249 	}
250 
251 	*mac_set_proc_data = intlabel;
252 	return (0);
253 }
254 
255 /*
256  * Actually sets the MAC label on 'newcred'.
257  *
258  * The current process' lock *must* be held.  This function only sets the label
259  * on 'newcred', but does not put 'newcred' in place on the current process'
260  * (consequently, it also does not call setsugid()).  'mac_set_proc_data' must
261  * be the pointer returned by mac_set_proc_prepare().  If called, this function
262  * must be so between a successful call to mac_set_proc_prepare() and
263  * mac_set_proc_finish(), but calling it is not mandatory (e.g., if some other
264  * error occured under the process lock that obsoletes setting the MAC label).
265  */
266 int
267 mac_set_proc_core(struct thread *const td, struct ucred *const newcred,
268     void *const mac_set_proc_data)
269 {
270 	struct label *const intlabel = mac_set_proc_data;
271 	struct proc *const p = td->td_proc;
272 	int error;
273 
274 	MPASS(td == curthread);
275 	PROC_LOCK_ASSERT(p, MA_OWNED);
276 
277 	error = mac_cred_check_relabel(p->p_ucred, intlabel);
278 	if (error)
279 		return (error);
280 
281 	mac_cred_relabel(newcred, intlabel);
282 	return (0);
283 }
284 
285 /*
286  * Performs mac_set_proc() last operations, without the process lock.
287  *
288  * 'proc_label_set' indicates whether the label was actually set by a call to
289  * mac_set_proc_core() that succeeded.  'mac_set_proc_data' must be the pointer
290  * returned by mac_set_proc_prepare(), and its associated data will be freed.
291  */
292 void
293 mac_set_proc_finish(struct thread *const td, bool proc_label_set,
294     void *const mac_set_proc_data)
295 {
296 	struct label *const intlabel = mac_set_proc_data;
297 
298 	PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
299 
300 	if (proc_label_set)
301 		mac_proc_vm_revoke(td);
302 	mac_cred_label_free(intlabel);
303 }
304 
305 int
306 mac_get_prison(struct thread *const td, struct prison *pr,
307     struct vfsoptlist *opts)
308 {
309 	char *buffer = NULL, *u_buffer;
310 	struct label *intlabel = NULL;
311 	struct mac mac;
312 	int error;
313 	bool locked = true;
314 
315 	mtx_assert(&pr->pr_mtx, MA_OWNED);
316 #ifdef COMPAT_FREEBSD32
317 	if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
318 		struct mac32 mac32;
319 
320 		error = vfs_copyopt(opts, "mac.label", &mac32, sizeof(mac32));
321 		if (error == 0) {
322 			CP(mac32, mac, m_buflen);
323 			PTRIN_CP(mac32, mac, m_string);
324 		}
325 	} else
326 #endif
327 		error = vfs_copyopt(opts, "mac.label", &mac, sizeof(mac));
328 	if (error) {
329 		if (error != ENOENT)
330 			vfs_opterror(opts, "bad mac.label");
331 		goto out_nomac;
332 	}
333 
334 	intlabel = mac_prison_label_alloc(M_NOWAIT);
335 	if (intlabel == NULL) {
336 		error = ENOMEM;
337 		goto out;
338 	}
339 
340 	if ((mac_labeled & MPC_OBJECT_PRISON) != 0)
341 		mac_prison_copy_label(pr->pr_label, intlabel);
342 
343 	/*
344 	 * Externalization may want to acquire an rmlock.  We already tapped out
345 	 * a copy of the label from when the jail_get(2) operation started and
346 	 * we're expected to be called near the end of jail_get(2) when the lock
347 	 * is about to be dropped anyways, so this is safe.
348 	 */
349 	mtx_unlock(&pr->pr_mtx);
350 	locked = false;
351 
352 	error = mac_label_copyin_string(&mac, &u_buffer, M_WAITOK);
353 	if (error) {
354 		vfs_opterror(opts, "mac.label: string copy failure");
355 		goto out;
356 	}
357 
358 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
359 	if (buffer == NULL) {
360 		error = ENOMEM;
361 		goto out;
362 	}
363 
364 	error = mac_prison_externalize_label(intlabel, mac.m_string,
365 	    buffer, mac.m_buflen);
366 
367 	if (error == 0)
368 		error = copyout(buffer, u_buffer, strlen(buffer)+1);
369 
370 out:
371 	mac_prison_label_free(intlabel);
372 	free_copied_label(&mac);
373 	free(buffer, M_MACTEMP);
374 
375 out_nomac:
376 	if (locked) {
377 		MPASS(error != 0);
378 		mtx_unlock(&pr->pr_mtx);
379 	}
380 
381 	return (error);
382 }
383 
384 int
385 mac_set_prison_prepare(struct thread *const td, struct vfsoptlist *opts,
386     void **const mac_set_prison_data)
387 {
388 	struct mac mac;
389 	struct label *intlabel;
390 	int error;
391 
392 #ifdef COMPAT_FREEBSD32
393 	if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
394 		struct mac32 mac32;
395 
396 		error = vfs_copyopt(opts, "mac.label", &mac32, sizeof(mac32));
397 		if (error == 0) {
398 			CP(mac32, mac, m_buflen);
399 			PTRIN_CP(mac32, mac, m_string);
400 		}
401 	} else
402 #endif
403 		error = vfs_copyopt(opts, "mac.label", &mac, sizeof(mac));
404 	if (error) {
405 		if (error != ENOENT)
406 			vfs_opterror(opts, "bad mac.label");
407 		return (error);
408 	}
409 
410 	error = mac_label_copyin_string(&mac, NULL, M_WAITOK);
411 	if (error) {
412 		vfs_opterror(opts, "mac.label: string copy failure");
413 		return (error);
414 	}
415 
416 	/*
417 	 * If the option wasn't set, then we return ENOENT above.  If we don't
418 	 * have any policies applicable to prisons, we can return EINVAL early.
419 	 */
420 	if (!(mac_labeled & MPC_OBJECT_PRISON)) {
421 		vfs_opterror(opts, "no labelled jail policies");
422 		return (EINVAL);
423 	}
424 
425 	intlabel = mac_prison_label_alloc(M_WAITOK);
426 	error = mac_prison_internalize_label(intlabel, mac.m_string);
427 	if (error) {
428 		mac_prison_label_free(intlabel);
429 		vfs_opterror(opts, "internalize_label error");
430 		return (error);
431 	}
432 
433 	*mac_set_prison_data = intlabel;
434 	return (0);
435 }
436 
437 int
438 mac_set_prison_core(struct thread *const td, struct prison *pr,
439     void *const mac_set_prison_data)
440 {
441 	struct label *const intlabel = mac_set_prison_data;
442 
443 	return (mac_prison_label_set(td->td_ucred, pr, intlabel));
444 }
445 
446 void
447 mac_set_prison_finish(struct thread *const td, bool prison_label_set __unused,
448     void *const mac_set_prison_data)
449 {
450 	struct label *const intlabel = mac_set_prison_data;
451 
452 	mac_prison_label_free(intlabel);
453 }
454 
455 int
456 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
457 {
458 	struct ucred *newcred, *oldcred;
459 	void *intlabel;
460 	struct proc *const p = td->td_proc;
461 	struct mac mac;
462 	int error;
463 
464 	error = mac_label_copyin(uap->mac_p, &mac, NULL);
465 	if (error)
466 		return (error);
467 
468 	error = mac_set_proc_prepare(td, &mac, &intlabel);
469 	if (error)
470 		goto free_label;
471 
472 	newcred = crget();
473 
474 	PROC_LOCK(p);
475 	oldcred = p->p_ucred;
476 	crcopy(newcred, oldcred);
477 
478 	error = mac_set_proc_core(td, newcred, intlabel);
479 	if (error) {
480 		PROC_UNLOCK(p);
481 		crfree(newcred);
482 		goto finish;
483 	}
484 
485 	setsugid(p);
486 	proc_set_cred(p, newcred);
487 	PROC_UNLOCK(p);
488 
489 	crfree(oldcred);
490 finish:
491 	mac_set_proc_finish(td, error == 0, intlabel);
492 free_label:
493 	free_copied_label(&mac);
494 	return (error);
495 }
496 
497 int
498 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
499 {
500 	char *u_buffer, *buffer;
501 	struct label *intlabel;
502 	struct file *fp;
503 	struct mac mac;
504 	struct vnode *vp;
505 	struct pipe *pipe;
506 	struct prison *pr;
507 	struct socket *so;
508 	cap_rights_t rights;
509 	int error;
510 
511 	error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
512 	if (error)
513 		return (error);
514 
515 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
516 	error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_GET),
517 	    &fp);
518 	if (error)
519 		goto out;
520 
521 	switch (fp->f_type) {
522 	case DTYPE_FIFO:
523 	case DTYPE_VNODE:
524 		if (!(mac_labeled & MPC_OBJECT_VNODE)) {
525 			error = EINVAL;
526 			goto out_fdrop;
527 		}
528 		vp = fp->f_vnode;
529 		intlabel = mac_vnode_label_alloc();
530 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
531 		mac_vnode_copy_label(vp->v_label, intlabel);
532 		VOP_UNLOCK(vp);
533 		error = mac_vnode_externalize_label(intlabel, mac.m_string,
534 		    buffer, mac.m_buflen);
535 		mac_vnode_label_free(intlabel);
536 		break;
537 
538 	case DTYPE_PIPE:
539 		if (!(mac_labeled & MPC_OBJECT_PIPE)) {
540 			error = EINVAL;
541 			goto out_fdrop;
542 		}
543 		pipe = fp->f_data;
544 		intlabel = mac_pipe_label_alloc();
545 		PIPE_LOCK(pipe);
546 		mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
547 		PIPE_UNLOCK(pipe);
548 		error = mac_pipe_externalize_label(intlabel, mac.m_string,
549 		    buffer, mac.m_buflen);
550 		mac_pipe_label_free(intlabel);
551 		break;
552 
553 	case DTYPE_SOCKET:
554 		if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
555 			error = EINVAL;
556 			goto out_fdrop;
557 		}
558 		so = fp->f_data;
559 		intlabel = mac_socket_label_alloc(M_WAITOK);
560 		SOCK_LOCK(so);
561 		mac_socket_copy_label(so->so_label, intlabel);
562 		SOCK_UNLOCK(so);
563 		error = mac_socket_externalize_label(intlabel, mac.m_string,
564 		    buffer, mac.m_buflen);
565 		mac_socket_label_free(intlabel);
566 		break;
567 
568 	case DTYPE_JAILDESC:
569 		if (!(mac_labeled & MPC_OBJECT_PRISON)) {
570 			error = EINVAL;
571 			goto out_fdrop;
572 		}
573 
574 		error = jaildesc_get_prison(fp, &pr);
575 		if (error != 0)
576 			goto out_fdrop;
577 
578 		intlabel = mac_prison_label_alloc(M_WAITOK);
579 		mac_prison_copy_label(pr->pr_label, intlabel);
580 		prison_free(pr);
581 
582 		error = mac_prison_externalize_label(intlabel, mac.m_string,
583 		    buffer, mac.m_buflen);
584 		mac_prison_label_free(intlabel);
585 		break;
586 
587 	default:
588 		error = EINVAL;
589 	}
590 	if (error == 0)
591 		error = copyout(buffer, u_buffer, strlen(buffer)+1);
592 out_fdrop:
593 	fdrop(fp, td);
594 out:
595 	free(buffer, M_MACTEMP);
596 	free_copied_label(&mac);
597 	return (error);
598 }
599 
600 int
601 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
602 {
603 
604 	return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW));
605 }
606 
607 int
608 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
609 {
610 
611 	return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
612 }
613 
614 static int
615 kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p,
616    int follow)
617 {
618 	char *u_buffer, *buffer;
619 	struct nameidata nd;
620 	struct label *intlabel;
621 	struct mac mac;
622 	int error;
623 
624 	if (!(mac_labeled & MPC_OBJECT_VNODE))
625 		return (EINVAL);
626 
627 	error = mac_label_copyin(mac_p, &mac, &u_buffer);
628 	if (error)
629 		return (error);
630 
631 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
632 	NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p);
633 	error = namei(&nd);
634 	if (error)
635 		goto out;
636 
637 	intlabel = mac_vnode_label_alloc();
638 	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
639 	error = mac_vnode_externalize_label(intlabel, mac.m_string, buffer,
640 	    mac.m_buflen);
641 	vput(nd.ni_vp);
642 	NDFREE_PNBUF(&nd);
643 	mac_vnode_label_free(intlabel);
644 
645 	if (error == 0)
646 		error = copyout(buffer, u_buffer, strlen(buffer)+1);
647 
648 out:
649 	free(buffer, M_MACTEMP);
650 	free_copied_label(&mac);
651 
652 	return (error);
653 }
654 
655 int
656 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
657 {
658 	struct label *intlabel;
659 	struct pipe *pipe;
660 	struct prison *pr;
661 	struct socket *so;
662 	struct file *fp;
663 	struct mount *mp;
664 	struct vnode *vp;
665 	struct mac mac;
666 	cap_rights_t rights;
667 	int error;
668 
669 	error = mac_label_copyin(uap->mac_p, &mac, NULL);
670 	if (error)
671 		return (error);
672 
673 	error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_SET),
674 	    &fp);
675 	if (error)
676 		goto out;
677 
678 	switch (fp->f_type) {
679 	case DTYPE_FIFO:
680 	case DTYPE_VNODE:
681 		if (!(mac_labeled & MPC_OBJECT_VNODE)) {
682 			error = EINVAL;
683 			goto out_fdrop;
684 		}
685 		intlabel = mac_vnode_label_alloc();
686 		error = mac_vnode_internalize_label(intlabel, mac.m_string);
687 		if (error) {
688 			mac_vnode_label_free(intlabel);
689 			break;
690 		}
691 		vp = fp->f_vnode;
692 		error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
693 		if (error != 0) {
694 			mac_vnode_label_free(intlabel);
695 			break;
696 		}
697 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
698 		error = vn_setlabel(vp, intlabel, td->td_ucred);
699 		VOP_UNLOCK(vp);
700 		vn_finished_write(mp);
701 		mac_vnode_label_free(intlabel);
702 		break;
703 
704 	case DTYPE_PIPE:
705 		if (!(mac_labeled & MPC_OBJECT_PIPE)) {
706 			error = EINVAL;
707 			goto out_fdrop;
708 		}
709 		intlabel = mac_pipe_label_alloc();
710 		error = mac_pipe_internalize_label(intlabel, mac.m_string);
711 		if (error == 0) {
712 			pipe = fp->f_data;
713 			PIPE_LOCK(pipe);
714 			error = mac_pipe_label_set(td->td_ucred,
715 			    pipe->pipe_pair, intlabel);
716 			PIPE_UNLOCK(pipe);
717 		}
718 		mac_pipe_label_free(intlabel);
719 		break;
720 
721 	case DTYPE_SOCKET:
722 		if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
723 			error = EINVAL;
724 			goto out_fdrop;
725 		}
726 		intlabel = mac_socket_label_alloc(M_WAITOK);
727 		error = mac_socket_internalize_label(intlabel, mac.m_string);
728 		if (error == 0) {
729 			so = fp->f_data;
730 			error = mac_socket_label_set(td->td_ucred, so,
731 			    intlabel);
732 		}
733 		mac_socket_label_free(intlabel);
734 		break;
735 
736 	case DTYPE_JAILDESC:
737 		if (!(mac_labeled & MPC_OBJECT_PRISON)) {
738 			error = EINVAL;
739 			goto out_fdrop;
740 		}
741 
742 		pr = NULL;
743 		intlabel = mac_prison_label_alloc(M_WAITOK);
744 		error = mac_prison_internalize_label(intlabel, mac.m_string);
745 		if (error == 0)
746 			error = jaildesc_get_prison(fp, &pr);
747 		if (error == 0) {
748 			prison_lock(pr);
749 			error = mac_prison_label_set(td->td_ucred, pr,
750 			    intlabel);
751 			prison_free_locked(pr);
752 		}
753 
754 		mac_prison_label_free(intlabel);
755 		break;
756 
757 	default:
758 		error = EINVAL;
759 	}
760 out_fdrop:
761 	fdrop(fp, td);
762 out:
763 	free_copied_label(&mac);
764 	return (error);
765 }
766 
767 int
768 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
769 {
770 
771 	return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW));
772 }
773 
774 int
775 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
776 {
777 
778 	return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
779 }
780 
781 static int
782 kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p,
783     int follow)
784 {
785 	struct label *intlabel;
786 	struct nameidata nd;
787 	struct mount *mp;
788 	struct mac mac;
789 	int error;
790 
791 	if (!(mac_labeled & MPC_OBJECT_VNODE))
792 		return (EINVAL);
793 
794 	error = mac_label_copyin(mac_p, &mac, NULL);
795 	if (error)
796 		return (error);
797 
798 	intlabel = mac_vnode_label_alloc();
799 	error = mac_vnode_internalize_label(intlabel, mac.m_string);
800 	free_copied_label(&mac);
801 	if (error)
802 		goto out;
803 
804 	NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p);
805 	error = namei(&nd);
806 	if (error == 0) {
807 		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
808 		if (error == 0) {
809 			error = vn_setlabel(nd.ni_vp, intlabel,
810 			    td->td_ucred);
811 			vn_finished_write(mp);
812 		}
813 		vput(nd.ni_vp);
814 		NDFREE_PNBUF(&nd);
815 	}
816 out:
817 	mac_vnode_label_free(intlabel);
818 	return (error);
819 }
820 
821 int
822 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
823 {
824 	struct mac_policy_conf *mpc;
825 	char target[MAC_MAX_POLICY_NAME];
826 	int error;
827 
828 	error = copyinstr(uap->policy, target, sizeof(target), NULL);
829 	if (error)
830 		return (error);
831 
832 	error = ENOSYS;
833 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
834 		if (strcmp(mpc->mpc_name, target) == 0 &&
835 		    mpc->mpc_ops->mpo_syscall != NULL) {
836 			error = mpc->mpc_ops->mpo_syscall(td,
837 			    uap->call, uap->arg);
838 			goto out;
839 		}
840 	}
841 
842 	if (!LIST_EMPTY(&mac_policy_list)) {
843 		mac_policy_slock_sleep();
844 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
845 			if (strcmp(mpc->mpc_name, target) == 0 &&
846 			    mpc->mpc_ops->mpo_syscall != NULL) {
847 				error = mpc->mpc_ops->mpo_syscall(td,
848 				    uap->call, uap->arg);
849 				break;
850 			}
851 		}
852 		mac_policy_sunlock_sleep();
853 	}
854 out:
855 	return (error);
856 }
857 
858 #else /* !MAC */
859 
860 int
861 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
862 {
863 
864 	return (ENOSYS);
865 }
866 
867 int
868 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
869 {
870 
871 	return (ENOSYS);
872 }
873 
874 int
875 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
876 {
877 
878 	return (ENOSYS);
879 }
880 
881 int
882 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
883 {
884 
885 	return (ENOSYS);
886 }
887 
888 int
889 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
890 {
891 
892 	return (ENOSYS);
893 }
894 
895 int
896 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
897 {
898 
899 	return (ENOSYS);
900 }
901 
902 int
903 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
904 {
905 
906 	return (ENOSYS);
907 }
908 
909 int
910 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
911 {
912 
913 	return (ENOSYS);
914 }
915 
916 int
917 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
918 {
919 
920 	return (ENOSYS);
921 }
922 
923 int
924 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
925 {
926 
927 	return (ENOSYS);
928 }
929 
930 #endif /* !MAC */
931