xref: /freebsd/sys/security/mac/mac_syscalls.c (revision 85dac03e30e6aebdf0808cd750cc5ab96efcb67c)
17bc82500SRobert Watson /*-
240202729SRobert Watson  * Copyright (c) 1999-2002, 2006, 2009 Robert N. M. Watson
37bc82500SRobert Watson  * Copyright (c) 2001 Ilmar S. Habibulin
4f0c2044bSRobert Watson  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5aed55708SRobert Watson  * Copyright (c) 2005-2006 SPARTA, Inc.
66356dba0SRobert Watson  * Copyright (c) 2008 Apple Inc.
77bc82500SRobert Watson  * All rights reserved.
87bc82500SRobert Watson  *
97bc82500SRobert Watson  * This software was developed by Robert Watson and Ilmar Habibulin for the
107bc82500SRobert Watson  * TrustedBSD Project.
117bc82500SRobert Watson  *
126201265bSRobert Watson  * This software was developed for the FreeBSD Project in part by Network
136201265bSRobert Watson  * Associates Laboratories, the Security Research Division of Network
146201265bSRobert Watson  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
156201265bSRobert Watson  * as part of the DARPA CHATS research program.
167bc82500SRobert Watson  *
1749bb6870SRobert Watson  * This software was enhanced by SPARTA ISSO under SPAWAR contract
1849bb6870SRobert Watson  * N66001-04-C-6019 ("SEFOS").
1949bb6870SRobert Watson  *
2040202729SRobert Watson  * This software was developed at the University of Cambridge Computer
2140202729SRobert Watson  * Laboratory with support from a grant from Google, Inc.
2240202729SRobert Watson  *
237bc82500SRobert Watson  * Redistribution and use in source and binary forms, with or without
247bc82500SRobert Watson  * modification, are permitted provided that the following conditions
257bc82500SRobert Watson  * are met:
267bc82500SRobert Watson  * 1. Redistributions of source code must retain the above copyright
277bc82500SRobert Watson  *    notice, this list of conditions and the following disclaimer.
287bc82500SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
297bc82500SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
307bc82500SRobert Watson  *    documentation and/or other materials provided with the distribution.
317bc82500SRobert Watson  *
327bc82500SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
337bc82500SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
347bc82500SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
357bc82500SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
367bc82500SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
377bc82500SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
387bc82500SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
397bc82500SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
407bc82500SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
417bc82500SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
427bc82500SRobert Watson  * SUCH DAMAGE.
437bc82500SRobert Watson  */
44677b542eSDavid E. O'Brien 
45677b542eSDavid E. O'Brien #include <sys/cdefs.h>
46677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
47677b542eSDavid E. O'Brien 
487bc82500SRobert Watson #include "opt_mac.h"
49f9d0d524SRobert Watson 
507bc82500SRobert Watson #include <sys/param.h>
514a144410SRobert Watson #include <sys/capsicum.h>
5257b4252eSKonstantin Belousov #include <sys/fcntl.h>
5395fab37eSRobert Watson #include <sys/kernel.h>
5495fab37eSRobert Watson #include <sys/lock.h>
55b656366bSBruce Evans #include <sys/malloc.h>
5695fab37eSRobert Watson #include <sys/mutex.h>
5795fab37eSRobert Watson #include <sys/mac.h>
5895fab37eSRobert Watson #include <sys/proc.h>
5995fab37eSRobert Watson #include <sys/systm.h>
60de5b1952SAlexander Leidinger #include <sys/sysctl.h>
617bc82500SRobert Watson #include <sys/sysproto.h>
6295fab37eSRobert Watson #include <sys/vnode.h>
6395fab37eSRobert Watson #include <sys/mount.h>
6495fab37eSRobert Watson #include <sys/file.h>
6595fab37eSRobert Watson #include <sys/namei.h>
6695fab37eSRobert Watson #include <sys/socket.h>
6795fab37eSRobert Watson #include <sys/pipe.h>
6895fab37eSRobert Watson #include <sys/socketvar.h>
6995fab37eSRobert Watson 
70aed55708SRobert Watson #include <security/mac/mac_framework.h>
716fa0475dSRobert Watson #include <security/mac/mac_internal.h>
720efd6615SRobert Watson #include <security/mac/mac_policy.h>
736fa0475dSRobert Watson 
7495fab37eSRobert Watson #ifdef MAC
7595fab37eSRobert Watson 
76d783bbd2SAlexander Leidinger FEATURE(security_mac, "Mandatory Access Control Framework support");
77de5b1952SAlexander Leidinger 
78d88fe103SBrooks Davis static int	kern___mac_get_path(struct thread *td, const char *path_p,
79d88fe103SBrooks Davis 		    struct mac *mac_p, int follow);
80d88fe103SBrooks Davis static int	kern___mac_set_path(struct thread *td, const char *path_p,
81d88fe103SBrooks Davis 		    struct mac *mac_p, int follow);
82d88fe103SBrooks Davis 
83f7b951a8SRobert Watson int
848451d0ddSKip Macy sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
85f7b951a8SRobert Watson {
86f7b951a8SRobert Watson 	char *elements, *buffer;
87f7b951a8SRobert Watson 	struct mac mac;
88f7b951a8SRobert Watson 	struct proc *tproc;
89f7b951a8SRobert Watson 	struct ucred *tcred;
90f7b951a8SRobert Watson 	int error;
91f7b951a8SRobert Watson 
92d1e405c5SAlfred Perlstein 	error = copyin(uap->mac_p, &mac, sizeof(mac));
93f7b951a8SRobert Watson 	if (error)
94f7b951a8SRobert Watson 		return (error);
95f7b951a8SRobert Watson 
96f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
97f7b951a8SRobert Watson 	if (error)
98f7b951a8SRobert Watson 		return (error);
99f7b951a8SRobert Watson 
100f7b951a8SRobert Watson 	tproc = pfind(uap->pid);
101f7b951a8SRobert Watson 	if (tproc == NULL)
102f7b951a8SRobert Watson 		return (ESRCH);
103f7b951a8SRobert Watson 
104f7b951a8SRobert Watson 	tcred = NULL;				/* Satisfy gcc. */
105f7b951a8SRobert Watson 	error = p_cansee(td, tproc);
106f7b951a8SRobert Watson 	if (error == 0)
107f7b951a8SRobert Watson 		tcred = crhold(tproc->p_ucred);
108f7b951a8SRobert Watson 	PROC_UNLOCK(tproc);
109f7b951a8SRobert Watson 	if (error)
110f7b951a8SRobert Watson 		return (error);
111f7b951a8SRobert Watson 
112a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
113f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
114f7b951a8SRobert Watson 	if (error) {
115f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
116f7b951a8SRobert Watson 		crfree(tcred);
117f7b951a8SRobert Watson 		return (error);
118f7b951a8SRobert Watson 	}
119f7b951a8SRobert Watson 
120a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
12130d239bcSRobert Watson 	error = mac_cred_externalize_label(tcred->cr_label, elements,
12283b7b0edSRobert Watson 	    buffer, mac.m_buflen);
123f7b951a8SRobert Watson 	if (error == 0)
124f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
125f7b951a8SRobert Watson 
126f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
127f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
128f7b951a8SRobert Watson 	crfree(tcred);
129f7b951a8SRobert Watson 	return (error);
130f7b951a8SRobert Watson }
131f7b951a8SRobert Watson 
13295fab37eSRobert Watson int
1338451d0ddSKip Macy sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
13495fab37eSRobert Watson {
135f7b951a8SRobert Watson 	char *elements, *buffer;
136f7b951a8SRobert Watson 	struct mac mac;
13795fab37eSRobert Watson 	int error;
13895fab37eSRobert Watson 
139f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
140f7b951a8SRobert Watson 	if (error)
141f7b951a8SRobert Watson 		return (error);
14295fab37eSRobert Watson 
143f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
144f7b951a8SRobert Watson 	if (error)
145f7b951a8SRobert Watson 		return (error);
146f7b951a8SRobert Watson 
147a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
148f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
149f7b951a8SRobert Watson 	if (error) {
150f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
151f7b951a8SRobert Watson 		return (error);
152f7b951a8SRobert Watson 	}
153f7b951a8SRobert Watson 
154a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
15530d239bcSRobert Watson 	error = mac_cred_externalize_label(td->td_ucred->cr_label,
15683b7b0edSRobert Watson 	    elements, buffer, mac.m_buflen);
157f7b951a8SRobert Watson 	if (error == 0)
158f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
159f7b951a8SRobert Watson 
160f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
161f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
16295fab37eSRobert Watson 	return (error);
16395fab37eSRobert Watson }
16495fab37eSRobert Watson 
16595fab37eSRobert Watson int
1668451d0ddSKip Macy sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
16795fab37eSRobert Watson {
16895fab37eSRobert Watson 	struct ucred *newcred, *oldcred;
169eca8a663SRobert Watson 	struct label *intlabel;
170f7b951a8SRobert Watson 	struct proc *p;
171f7b951a8SRobert Watson 	struct mac mac;
172f7b951a8SRobert Watson 	char *buffer;
17395fab37eSRobert Watson 	int error;
17495fab37eSRobert Watson 
1756356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_CRED))
1766356dba0SRobert Watson 		return (EINVAL);
1776356dba0SRobert Watson 
178f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
17995fab37eSRobert Watson 	if (error)
18095fab37eSRobert Watson 		return (error);
18195fab37eSRobert Watson 
182f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
18395fab37eSRobert Watson 	if (error)
18495fab37eSRobert Watson 		return (error);
18595fab37eSRobert Watson 
186a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
187f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
188f7b951a8SRobert Watson 	if (error) {
189f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
190f7b951a8SRobert Watson 		return (error);
191f7b951a8SRobert Watson 	}
192f7b951a8SRobert Watson 
193eca8a663SRobert Watson 	intlabel = mac_cred_label_alloc();
19430d239bcSRobert Watson 	error = mac_cred_internalize_label(intlabel, buffer);
195f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
196eca8a663SRobert Watson 	if (error)
197eca8a663SRobert Watson 		goto out;
198f7b951a8SRobert Watson 
19995fab37eSRobert Watson 	newcred = crget();
20095fab37eSRobert Watson 
20195fab37eSRobert Watson 	p = td->td_proc;
20295fab37eSRobert Watson 	PROC_LOCK(p);
20395fab37eSRobert Watson 	oldcred = p->p_ucred;
20495fab37eSRobert Watson 
20530d239bcSRobert Watson 	error = mac_cred_check_relabel(oldcred, intlabel);
20695fab37eSRobert Watson 	if (error) {
20795fab37eSRobert Watson 		PROC_UNLOCK(p);
20895fab37eSRobert Watson 		crfree(newcred);
209f7b951a8SRobert Watson 		goto out;
21095fab37eSRobert Watson 	}
21195fab37eSRobert Watson 
21295fab37eSRobert Watson 	setsugid(p);
21395fab37eSRobert Watson 	crcopy(newcred, oldcred);
21430d239bcSRobert Watson 	mac_cred_relabel(newcred, intlabel);
215daf63fd2SMateusz Guzik 	proc_set_cred(p, newcred);
216e5cb5e37SRobert Watson 
21795fab37eSRobert Watson 	PROC_UNLOCK(p);
21895fab37eSRobert Watson 	crfree(oldcred);
2199215889dSRobert Watson 	mac_proc_vm_revoke(td);
220f7b951a8SRobert Watson 
221f7b951a8SRobert Watson out:
222eca8a663SRobert Watson 	mac_cred_label_free(intlabel);
223f7b951a8SRobert Watson 	return (error);
22495fab37eSRobert Watson }
22595fab37eSRobert Watson 
22695fab37eSRobert Watson int
2278451d0ddSKip Macy sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
22895fab37eSRobert Watson {
229f7b951a8SRobert Watson 	char *elements, *buffer;
230eca8a663SRobert Watson 	struct label *intlabel;
23195fab37eSRobert Watson 	struct file *fp;
232f7b951a8SRobert Watson 	struct mac mac;
23395fab37eSRobert Watson 	struct vnode *vp;
23495fab37eSRobert Watson 	struct pipe *pipe;
235b0323ea3SRobert Watson 	struct socket *so;
2367008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
2375050aa86SKonstantin Belousov 	int error;
23895fab37eSRobert Watson 
239f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
240f7b951a8SRobert Watson 	if (error)
241f7b951a8SRobert Watson 		return (error);
24295fab37eSRobert Watson 
243f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
244f7b951a8SRobert Watson 	if (error)
245f7b951a8SRobert Watson 		return (error);
246f7b951a8SRobert Watson 
247a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
248f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
249f7b951a8SRobert Watson 	if (error) {
250f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
251f7b951a8SRobert Watson 		return (error);
252f7b951a8SRobert Watson 	}
253f7b951a8SRobert Watson 
254a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
2556b3a9a0fSMateusz Guzik 	error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_GET),
2566b3a9a0fSMateusz Guzik 	    &fp);
25795fab37eSRobert Watson 	if (error)
25895fab37eSRobert Watson 		goto out;
25995fab37eSRobert Watson 
26095fab37eSRobert Watson 	switch (fp->f_type) {
26195fab37eSRobert Watson 	case DTYPE_FIFO:
26295fab37eSRobert Watson 	case DTYPE_VNODE:
263b4ef8be2SRobert Watson 		if (!(mac_labeled & MPC_OBJECT_VNODE)) {
264b4ef8be2SRobert Watson 			error = EINVAL;
265b4ef8be2SRobert Watson 			goto out_fdrop;
266b4ef8be2SRobert Watson 		}
2673b6d9652SPoul-Henning Kamp 		vp = fp->f_vnode;
268eca8a663SRobert Watson 		intlabel = mac_vnode_label_alloc();
269cb05b60aSAttilio Rao 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
27030d239bcSRobert Watson 		mac_vnode_copy_label(vp->v_label, intlabel);
271b249ce48SMateusz Guzik 		VOP_UNLOCK(vp);
27230d239bcSRobert Watson 		error = mac_vnode_externalize_label(intlabel, elements,
273f0ab0442SRobert Watson 		    buffer, mac.m_buflen);
274f0ab0442SRobert Watson 		mac_vnode_label_free(intlabel);
27595fab37eSRobert Watson 		break;
276f0ab0442SRobert Watson 
27795fab37eSRobert Watson 	case DTYPE_PIPE:
278b4ef8be2SRobert Watson 		if (!(mac_labeled & MPC_OBJECT_PIPE)) {
279b4ef8be2SRobert Watson 			error = EINVAL;
280b4ef8be2SRobert Watson 			goto out_fdrop;
281b4ef8be2SRobert Watson 		}
28248e3128bSMatthew Dillon 		pipe = fp->f_data;
283eca8a663SRobert Watson 		intlabel = mac_pipe_label_alloc();
284f7b951a8SRobert Watson 		PIPE_LOCK(pipe);
28530d239bcSRobert Watson 		mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
286f7b951a8SRobert Watson 		PIPE_UNLOCK(pipe);
28730d239bcSRobert Watson 		error = mac_pipe_externalize_label(intlabel, elements,
28883b7b0edSRobert Watson 		    buffer, mac.m_buflen);
289eca8a663SRobert Watson 		mac_pipe_label_free(intlabel);
290f7b951a8SRobert Watson 		break;
29195fab37eSRobert Watson 
292b0323ea3SRobert Watson 	case DTYPE_SOCKET:
293b4ef8be2SRobert Watson 		if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
294b4ef8be2SRobert Watson 			error = EINVAL;
295b4ef8be2SRobert Watson 			goto out_fdrop;
296b4ef8be2SRobert Watson 		}
297b0323ea3SRobert Watson 		so = fp->f_data;
298b0323ea3SRobert Watson 		intlabel = mac_socket_label_alloc(M_WAITOK);
299f0c2044bSRobert Watson 		SOCK_LOCK(so);
30030d239bcSRobert Watson 		mac_socket_copy_label(so->so_label, intlabel);
301f0c2044bSRobert Watson 		SOCK_UNLOCK(so);
30230d239bcSRobert Watson 		error = mac_socket_externalize_label(intlabel, elements,
303b0323ea3SRobert Watson 		    buffer, mac.m_buflen);
304b0323ea3SRobert Watson 		mac_socket_label_free(intlabel);
305b0323ea3SRobert Watson 		break;
306b0323ea3SRobert Watson 
307f0ab0442SRobert Watson 	default:
308f0ab0442SRobert Watson 		error = EINVAL;
309f0ab0442SRobert Watson 	}
31095fab37eSRobert Watson 	if (error == 0)
311f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
312b4ef8be2SRobert Watson out_fdrop:
313b4ef8be2SRobert Watson 	fdrop(fp, td);
31495fab37eSRobert Watson out:
315f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
316f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
31795fab37eSRobert Watson 	return (error);
31895fab37eSRobert Watson }
31995fab37eSRobert Watson 
32095fab37eSRobert Watson int
3218451d0ddSKip Macy sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
32295fab37eSRobert Watson {
32395fab37eSRobert Watson 
324d88fe103SBrooks Davis 	return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW));
325f7b951a8SRobert Watson }
326f7b951a8SRobert Watson 
327f7b951a8SRobert Watson int
3288451d0ddSKip Macy sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
329f7b951a8SRobert Watson {
330d88fe103SBrooks Davis 
331d88fe103SBrooks Davis 	return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
332d88fe103SBrooks Davis }
333d88fe103SBrooks Davis 
334d88fe103SBrooks Davis static int
335d88fe103SBrooks Davis kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p,
336d88fe103SBrooks Davis    int follow)
337d88fe103SBrooks Davis {
338f7b951a8SRobert Watson 	char *elements, *buffer;
339f7b951a8SRobert Watson 	struct nameidata nd;
340eca8a663SRobert Watson 	struct label *intlabel;
341f7b951a8SRobert Watson 	struct mac mac;
3425050aa86SKonstantin Belousov 	int error;
343f7b951a8SRobert Watson 
3446356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_VNODE))
3456356dba0SRobert Watson 		return (EINVAL);
3466356dba0SRobert Watson 
347d88fe103SBrooks Davis 	error = copyin(mac_p, &mac, sizeof(mac));
348f7b951a8SRobert Watson 	if (error)
349f7b951a8SRobert Watson 		return (error);
350f7b951a8SRobert Watson 
351f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
352f7b951a8SRobert Watson 	if (error)
353f7b951a8SRobert Watson 		return (error);
354f7b951a8SRobert Watson 
355a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
356f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
357f7b951a8SRobert Watson 	if (error) {
358f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
359f7b951a8SRobert Watson 		return (error);
360f7b951a8SRobert Watson 	}
361f7b951a8SRobert Watson 
362a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
3637e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p);
364f7b951a8SRobert Watson 	error = namei(&nd);
36595fab37eSRobert Watson 	if (error)
36695fab37eSRobert Watson 		goto out;
36795fab37eSRobert Watson 
368eca8a663SRobert Watson 	intlabel = mac_vnode_label_alloc();
36930d239bcSRobert Watson 	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
37030d239bcSRobert Watson 	error = mac_vnode_externalize_label(intlabel, elements, buffer,
37183b7b0edSRobert Watson 	    mac.m_buflen);
372*85dac03eSMateusz Guzik 	vput(nd.ni_vp);
373*85dac03eSMateusz Guzik 	NDFREE_PNBUF(&nd);
374eca8a663SRobert Watson 	mac_vnode_label_free(intlabel);
375f7b951a8SRobert Watson 
376f7b951a8SRobert Watson 	if (error == 0)
377f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
37895fab37eSRobert Watson 
37995fab37eSRobert Watson out:
380f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
381f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
382f7b951a8SRobert Watson 
38395fab37eSRobert Watson 	return (error);
38495fab37eSRobert Watson }
38595fab37eSRobert Watson 
38695fab37eSRobert Watson int
3878451d0ddSKip Macy sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
38895fab37eSRobert Watson {
389eca8a663SRobert Watson 	struct label *intlabel;
390f7b951a8SRobert Watson 	struct pipe *pipe;
391b0323ea3SRobert Watson 	struct socket *so;
392f7b951a8SRobert Watson 	struct file *fp;
39395fab37eSRobert Watson 	struct mount *mp;
39495fab37eSRobert Watson 	struct vnode *vp;
395f7b951a8SRobert Watson 	struct mac mac;
3967008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
397f7b951a8SRobert Watson 	char *buffer;
3985050aa86SKonstantin Belousov 	int error;
39995fab37eSRobert Watson 
400f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
401f7b951a8SRobert Watson 	if (error)
402f7b951a8SRobert Watson 		return (error);
403f7b951a8SRobert Watson 
404f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
405f7b951a8SRobert Watson 	if (error)
406f7b951a8SRobert Watson 		return (error);
407f7b951a8SRobert Watson 
408a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
409f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
410f7b951a8SRobert Watson 	if (error) {
411f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
412f7b951a8SRobert Watson 		return (error);
413f7b951a8SRobert Watson 	}
414f7b951a8SRobert Watson 
4156b3a9a0fSMateusz Guzik 	error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_SET),
4166b3a9a0fSMateusz Guzik 	    &fp);
41795fab37eSRobert Watson 	if (error)
418f7b951a8SRobert Watson 		goto out;
41995fab37eSRobert Watson 
42095fab37eSRobert Watson 	switch (fp->f_type) {
42195fab37eSRobert Watson 	case DTYPE_FIFO:
42295fab37eSRobert Watson 	case DTYPE_VNODE:
423b4ef8be2SRobert Watson 		if (!(mac_labeled & MPC_OBJECT_VNODE)) {
424b4ef8be2SRobert Watson 			error = EINVAL;
425b4ef8be2SRobert Watson 			goto out_fdrop;
426b4ef8be2SRobert Watson 		}
427eca8a663SRobert Watson 		intlabel = mac_vnode_label_alloc();
42830d239bcSRobert Watson 		error = mac_vnode_internalize_label(intlabel, buffer);
429f7b951a8SRobert Watson 		if (error) {
430eca8a663SRobert Watson 			mac_vnode_label_free(intlabel);
431f7b951a8SRobert Watson 			break;
432f7b951a8SRobert Watson 		}
4333b6d9652SPoul-Henning Kamp 		vp = fp->f_vnode;
434a75d1dddSMateusz Guzik 		error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
435f7b951a8SRobert Watson 		if (error != 0) {
436eca8a663SRobert Watson 			mac_vnode_label_free(intlabel);
43795fab37eSRobert Watson 			break;
438f7b951a8SRobert Watson 		}
439cb05b60aSAttilio Rao 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
440eca8a663SRobert Watson 		error = vn_setlabel(vp, intlabel, td->td_ucred);
441b249ce48SMateusz Guzik 		VOP_UNLOCK(vp);
44295fab37eSRobert Watson 		vn_finished_write(mp);
443eca8a663SRobert Watson 		mac_vnode_label_free(intlabel);
44495fab37eSRobert Watson 		break;
445f7b951a8SRobert Watson 
44695fab37eSRobert Watson 	case DTYPE_PIPE:
447b4ef8be2SRobert Watson 		if (!(mac_labeled & MPC_OBJECT_PIPE)) {
448b4ef8be2SRobert Watson 			error = EINVAL;
449b4ef8be2SRobert Watson 			goto out_fdrop;
450b4ef8be2SRobert Watson 		}
451eca8a663SRobert Watson 		intlabel = mac_pipe_label_alloc();
45230d239bcSRobert Watson 		error = mac_pipe_internalize_label(intlabel, buffer);
453f7b951a8SRobert Watson 		if (error == 0) {
45448e3128bSMatthew Dillon 			pipe = fp->f_data;
4551aa37f53SRobert Watson 			PIPE_LOCK(pipe);
4564795b82cSRobert Watson 			error = mac_pipe_label_set(td->td_ucred,
4574795b82cSRobert Watson 			    pipe->pipe_pair, intlabel);
4581aa37f53SRobert Watson 			PIPE_UNLOCK(pipe);
459f7b951a8SRobert Watson 		}
460eca8a663SRobert Watson 		mac_pipe_label_free(intlabel);
46195fab37eSRobert Watson 		break;
462f7b951a8SRobert Watson 
463b0323ea3SRobert Watson 	case DTYPE_SOCKET:
464b4ef8be2SRobert Watson 		if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
465b4ef8be2SRobert Watson 			error = EINVAL;
466b4ef8be2SRobert Watson 			goto out_fdrop;
467b4ef8be2SRobert Watson 		}
468b0323ea3SRobert Watson 		intlabel = mac_socket_label_alloc(M_WAITOK);
46930d239bcSRobert Watson 		error = mac_socket_internalize_label(intlabel, buffer);
470b0323ea3SRobert Watson 		if (error == 0) {
471b0323ea3SRobert Watson 			so = fp->f_data;
472b0323ea3SRobert Watson 			error = mac_socket_label_set(td->td_ucred, so,
473b0323ea3SRobert Watson 			    intlabel);
474b0323ea3SRobert Watson 		}
475b0323ea3SRobert Watson 		mac_socket_label_free(intlabel);
476b0323ea3SRobert Watson 		break;
477b0323ea3SRobert Watson 
47895fab37eSRobert Watson 	default:
47995fab37eSRobert Watson 		error = EINVAL;
48095fab37eSRobert Watson 	}
481b4ef8be2SRobert Watson out_fdrop:
48295fab37eSRobert Watson 	fdrop(fp, td);
483f7b951a8SRobert Watson out:
484f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
48595fab37eSRobert Watson 	return (error);
48695fab37eSRobert Watson }
48795fab37eSRobert Watson 
48895fab37eSRobert Watson int
4898451d0ddSKip Macy sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
49095fab37eSRobert Watson {
49195fab37eSRobert Watson 
492d88fe103SBrooks Davis 	return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW));
493f7b951a8SRobert Watson }
494f7b951a8SRobert Watson 
495f7b951a8SRobert Watson int
4968451d0ddSKip Macy sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
497f7b951a8SRobert Watson {
498d88fe103SBrooks Davis 
499d88fe103SBrooks Davis 	return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
500d88fe103SBrooks Davis }
501d88fe103SBrooks Davis 
502d88fe103SBrooks Davis static int
503d88fe103SBrooks Davis kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p,
504d88fe103SBrooks Davis     int follow)
505d88fe103SBrooks Davis {
506eca8a663SRobert Watson 	struct label *intlabel;
507f7b951a8SRobert Watson 	struct nameidata nd;
508f7b951a8SRobert Watson 	struct mount *mp;
509f7b951a8SRobert Watson 	struct mac mac;
510f7b951a8SRobert Watson 	char *buffer;
5115050aa86SKonstantin Belousov 	int error;
512f7b951a8SRobert Watson 
5136356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_VNODE))
5146356dba0SRobert Watson 		return (EINVAL);
5156356dba0SRobert Watson 
516d88fe103SBrooks Davis 	error = copyin(mac_p, &mac, sizeof(mac));
517f7b951a8SRobert Watson 	if (error)
518f7b951a8SRobert Watson 		return (error);
519f7b951a8SRobert Watson 
520f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
521f7b951a8SRobert Watson 	if (error)
522f7b951a8SRobert Watson 		return (error);
523f7b951a8SRobert Watson 
524a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
525f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
526f7b951a8SRobert Watson 	if (error) {
527f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
528f7b951a8SRobert Watson 		return (error);
529f7b951a8SRobert Watson 	}
530f7b951a8SRobert Watson 
531eca8a663SRobert Watson 	intlabel = mac_vnode_label_alloc();
53230d239bcSRobert Watson 	error = mac_vnode_internalize_label(intlabel, buffer);
533f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
534eca8a663SRobert Watson 	if (error)
535eca8a663SRobert Watson 		goto out;
536f7b951a8SRobert Watson 
5377e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p);
538f7b951a8SRobert Watson 	error = namei(&nd);
539f7b951a8SRobert Watson 	if (error == 0) {
540a75d1dddSMateusz Guzik 		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
541d50ef66dSTor Egge 		if (error == 0) {
542eca8a663SRobert Watson 			error = vn_setlabel(nd.ni_vp, intlabel,
543f7b951a8SRobert Watson 			    td->td_ucred);
544f7b951a8SRobert Watson 			vn_finished_write(mp);
545f7b951a8SRobert Watson 		}
546*85dac03eSMateusz Guzik 		vput(nd.ni_vp);
547*85dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
548d50ef66dSTor Egge 	}
549eca8a663SRobert Watson out:
550eca8a663SRobert Watson 	mac_vnode_label_free(intlabel);
551f7b951a8SRobert Watson 	return (error);
552f7b951a8SRobert Watson }
553f7b951a8SRobert Watson 
55427f2eac7SRobert Watson int
5558451d0ddSKip Macy sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
55627f2eac7SRobert Watson {
55727f2eac7SRobert Watson 	struct mac_policy_conf *mpc;
55827f2eac7SRobert Watson 	char target[MAC_MAX_POLICY_NAME];
55940202729SRobert Watson 	int error;
56027f2eac7SRobert Watson 
561d1e405c5SAlfred Perlstein 	error = copyinstr(uap->policy, target, sizeof(target), NULL);
56227f2eac7SRobert Watson 	if (error)
56327f2eac7SRobert Watson 		return (error);
56427f2eac7SRobert Watson 
56527f2eac7SRobert Watson 	error = ENOSYS;
566a6a65b05SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
56727f2eac7SRobert Watson 		if (strcmp(mpc->mpc_name, target) == 0 &&
56827f2eac7SRobert Watson 		    mpc->mpc_ops->mpo_syscall != NULL) {
56927f2eac7SRobert Watson 			error = mpc->mpc_ops->mpo_syscall(td,
570d1e405c5SAlfred Perlstein 			    uap->call, uap->arg);
57127f2eac7SRobert Watson 			goto out;
57227f2eac7SRobert Watson 		}
57327f2eac7SRobert Watson 	}
57427f2eac7SRobert Watson 
57540202729SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {
57640202729SRobert Watson 		mac_policy_slock_sleep();
57741a17fe3SRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
57841a17fe3SRobert Watson 			if (strcmp(mpc->mpc_name, target) == 0 &&
57941a17fe3SRobert Watson 			    mpc->mpc_ops->mpo_syscall != NULL) {
58041a17fe3SRobert Watson 				error = mpc->mpc_ops->mpo_syscall(td,
58141a17fe3SRobert Watson 				    uap->call, uap->arg);
58241a17fe3SRobert Watson 				break;
58341a17fe3SRobert Watson 			}
58441a17fe3SRobert Watson 		}
58540202729SRobert Watson 		mac_policy_sunlock_sleep();
58641a17fe3SRobert Watson 	}
58727f2eac7SRobert Watson out:
58827f2eac7SRobert Watson 	return (error);
58927f2eac7SRobert Watson }
59027f2eac7SRobert Watson 
59195fab37eSRobert Watson #else /* !MAC */
5927bc82500SRobert Watson 
5937bc82500SRobert Watson int
5948451d0ddSKip Macy sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
595f7b951a8SRobert Watson {
596f7b951a8SRobert Watson 
597f7b951a8SRobert Watson 	return (ENOSYS);
598f7b951a8SRobert Watson }
599f7b951a8SRobert Watson 
600f7b951a8SRobert Watson int
6018451d0ddSKip Macy sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
6027bc82500SRobert Watson {
6037bc82500SRobert Watson 
6047bc82500SRobert Watson 	return (ENOSYS);
6057bc82500SRobert Watson }
6067bc82500SRobert Watson 
6077bc82500SRobert Watson int
6088451d0ddSKip Macy sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
6097bc82500SRobert Watson {
6107bc82500SRobert Watson 
6117bc82500SRobert Watson 	return (ENOSYS);
6127bc82500SRobert Watson }
6137bc82500SRobert Watson 
6147bc82500SRobert Watson int
6158451d0ddSKip Macy sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
6167bc82500SRobert Watson {
6177bc82500SRobert Watson 
6187bc82500SRobert Watson 	return (ENOSYS);
6197bc82500SRobert Watson }
6207bc82500SRobert Watson 
6217bc82500SRobert Watson int
6228451d0ddSKip Macy sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
6237bc82500SRobert Watson {
6247bc82500SRobert Watson 
6257bc82500SRobert Watson 	return (ENOSYS);
6267bc82500SRobert Watson }
6277bc82500SRobert Watson 
6287bc82500SRobert Watson int
6298451d0ddSKip Macy sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
630f7b951a8SRobert Watson {
631f7b951a8SRobert Watson 
632f7b951a8SRobert Watson 	return (ENOSYS);
633f7b951a8SRobert Watson }
634f7b951a8SRobert Watson 
635f7b951a8SRobert Watson int
6368451d0ddSKip Macy sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
6377bc82500SRobert Watson {
6387bc82500SRobert Watson 
6397bc82500SRobert Watson 	return (ENOSYS);
6407bc82500SRobert Watson }
6417bc82500SRobert Watson 
6427bc82500SRobert Watson int
6438451d0ddSKip Macy sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
6447bc82500SRobert Watson {
6457bc82500SRobert Watson 
6467bc82500SRobert Watson 	return (ENOSYS);
6477bc82500SRobert Watson }
64895fab37eSRobert Watson 
64927f2eac7SRobert Watson int
6508451d0ddSKip Macy sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
651f7b951a8SRobert Watson {
652f7b951a8SRobert Watson 
653f7b951a8SRobert Watson 	return (ENOSYS);
654f7b951a8SRobert Watson }
655f7b951a8SRobert Watson 
656f7b951a8SRobert Watson int
6578451d0ddSKip Macy sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
65827f2eac7SRobert Watson {
65927f2eac7SRobert Watson 
66027f2eac7SRobert Watson 	return (ENOSYS);
66127f2eac7SRobert Watson }
66227f2eac7SRobert Watson 
66319b78822SRobert Watson #endif /* !MAC */
664