xref: /f-stack/freebsd/security/mac/mac_syscalls.c (revision 22ce4aff)
1a9643ea8Slogwang /*-
2a9643ea8Slogwang  * Copyright (c) 1999-2002, 2006, 2009 Robert N. M. Watson
3a9643ea8Slogwang  * Copyright (c) 2001 Ilmar S. Habibulin
4a9643ea8Slogwang  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5a9643ea8Slogwang  * Copyright (c) 2005-2006 SPARTA, Inc.
6a9643ea8Slogwang  * Copyright (c) 2008 Apple Inc.
7a9643ea8Slogwang  * All rights reserved.
8a9643ea8Slogwang  *
9a9643ea8Slogwang  * This software was developed by Robert Watson and Ilmar Habibulin for the
10a9643ea8Slogwang  * TrustedBSD Project.
11a9643ea8Slogwang  *
12a9643ea8Slogwang  * This software was developed for the FreeBSD Project in part by Network
13a9643ea8Slogwang  * Associates Laboratories, the Security Research Division of Network
14a9643ea8Slogwang  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15a9643ea8Slogwang  * as part of the DARPA CHATS research program.
16a9643ea8Slogwang  *
17a9643ea8Slogwang  * This software was enhanced by SPARTA ISSO under SPAWAR contract
18a9643ea8Slogwang  * N66001-04-C-6019 ("SEFOS").
19a9643ea8Slogwang  *
20a9643ea8Slogwang  * This software was developed at the University of Cambridge Computer
21a9643ea8Slogwang  * Laboratory with support from a grant from Google, Inc.
22a9643ea8Slogwang  *
23a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or without
24a9643ea8Slogwang  * modification, are permitted provided that the following conditions
25a9643ea8Slogwang  * are met:
26a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
27a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer.
28a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
29a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer in the
30a9643ea8Slogwang  *    documentation and/or other materials provided with the distribution.
31a9643ea8Slogwang  *
32a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33a9643ea8Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34a9643ea8Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35a9643ea8Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36a9643ea8Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37a9643ea8Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38a9643ea8Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39a9643ea8Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40a9643ea8Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41a9643ea8Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42a9643ea8Slogwang  * SUCH DAMAGE.
43a9643ea8Slogwang  */
44a9643ea8Slogwang 
45a9643ea8Slogwang #include <sys/cdefs.h>
46a9643ea8Slogwang __FBSDID("$FreeBSD$");
47a9643ea8Slogwang 
48a9643ea8Slogwang #include "opt_mac.h"
49a9643ea8Slogwang 
50a9643ea8Slogwang #include <sys/param.h>
51a9643ea8Slogwang #include <sys/capsicum.h>
52a9643ea8Slogwang #include <sys/fcntl.h>
53a9643ea8Slogwang #include <sys/kernel.h>
54a9643ea8Slogwang #include <sys/lock.h>
55a9643ea8Slogwang #include <sys/malloc.h>
56a9643ea8Slogwang #include <sys/mutex.h>
57a9643ea8Slogwang #include <sys/mac.h>
58a9643ea8Slogwang #include <sys/proc.h>
59a9643ea8Slogwang #include <sys/systm.h>
60a9643ea8Slogwang #include <sys/sysctl.h>
61a9643ea8Slogwang #include <sys/sysproto.h>
62a9643ea8Slogwang #include <sys/sysent.h>
63a9643ea8Slogwang #include <sys/vnode.h>
64a9643ea8Slogwang #include <sys/mount.h>
65a9643ea8Slogwang #include <sys/file.h>
66a9643ea8Slogwang #include <sys/namei.h>
67a9643ea8Slogwang #include <sys/socket.h>
68a9643ea8Slogwang #include <sys/pipe.h>
69a9643ea8Slogwang #include <sys/socketvar.h>
70a9643ea8Slogwang 
71a9643ea8Slogwang #include <security/mac/mac_framework.h>
72a9643ea8Slogwang #include <security/mac/mac_internal.h>
73a9643ea8Slogwang #include <security/mac/mac_policy.h>
74a9643ea8Slogwang 
75a9643ea8Slogwang #ifdef MAC
76a9643ea8Slogwang 
77a9643ea8Slogwang FEATURE(security_mac, "Mandatory Access Control Framework support");
78a9643ea8Slogwang 
79*22ce4affSfengbojiang static int	kern___mac_get_path(struct thread *td, const char *path_p,
80*22ce4affSfengbojiang 		    struct mac *mac_p, int follow);
81*22ce4affSfengbojiang static int	kern___mac_set_path(struct thread *td, const char *path_p,
82*22ce4affSfengbojiang 		    struct mac *mac_p, int follow);
83*22ce4affSfengbojiang 
84a9643ea8Slogwang int
sys___mac_get_pid(struct thread * td,struct __mac_get_pid_args * uap)85a9643ea8Slogwang sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
86a9643ea8Slogwang {
87a9643ea8Slogwang 	char *elements, *buffer;
88a9643ea8Slogwang 	struct mac mac;
89a9643ea8Slogwang 	struct proc *tproc;
90a9643ea8Slogwang 	struct ucred *tcred;
91a9643ea8Slogwang 	int error;
92a9643ea8Slogwang 
93a9643ea8Slogwang 	error = copyin(uap->mac_p, &mac, sizeof(mac));
94a9643ea8Slogwang 	if (error)
95a9643ea8Slogwang 		return (error);
96a9643ea8Slogwang 
97a9643ea8Slogwang 	error = mac_check_structmac_consistent(&mac);
98a9643ea8Slogwang 	if (error)
99a9643ea8Slogwang 		return (error);
100a9643ea8Slogwang 
101a9643ea8Slogwang 	tproc = pfind(uap->pid);
102a9643ea8Slogwang 	if (tproc == NULL)
103a9643ea8Slogwang 		return (ESRCH);
104a9643ea8Slogwang 
105a9643ea8Slogwang 	tcred = NULL;				/* Satisfy gcc. */
106a9643ea8Slogwang 	error = p_cansee(td, tproc);
107a9643ea8Slogwang 	if (error == 0)
108a9643ea8Slogwang 		tcred = crhold(tproc->p_ucred);
109a9643ea8Slogwang 	PROC_UNLOCK(tproc);
110a9643ea8Slogwang 	if (error)
111a9643ea8Slogwang 		return (error);
112a9643ea8Slogwang 
113a9643ea8Slogwang 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
114a9643ea8Slogwang 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
115a9643ea8Slogwang 	if (error) {
116a9643ea8Slogwang 		free(elements, M_MACTEMP);
117a9643ea8Slogwang 		crfree(tcred);
118a9643ea8Slogwang 		return (error);
119a9643ea8Slogwang 	}
120a9643ea8Slogwang 
121a9643ea8Slogwang 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
122a9643ea8Slogwang 	error = mac_cred_externalize_label(tcred->cr_label, elements,
123a9643ea8Slogwang 	    buffer, mac.m_buflen);
124a9643ea8Slogwang 	if (error == 0)
125a9643ea8Slogwang 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
126a9643ea8Slogwang 
127a9643ea8Slogwang 	free(buffer, M_MACTEMP);
128a9643ea8Slogwang 	free(elements, M_MACTEMP);
129a9643ea8Slogwang 	crfree(tcred);
130a9643ea8Slogwang 	return (error);
131a9643ea8Slogwang }
132a9643ea8Slogwang 
133a9643ea8Slogwang int
sys___mac_get_proc(struct thread * td,struct __mac_get_proc_args * uap)134a9643ea8Slogwang sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
135a9643ea8Slogwang {
136a9643ea8Slogwang 	char *elements, *buffer;
137a9643ea8Slogwang 	struct mac mac;
138a9643ea8Slogwang 	int error;
139a9643ea8Slogwang 
140a9643ea8Slogwang 	error = copyin(uap->mac_p, &mac, sizeof(mac));
141a9643ea8Slogwang 	if (error)
142a9643ea8Slogwang 		return (error);
143a9643ea8Slogwang 
144a9643ea8Slogwang 	error = mac_check_structmac_consistent(&mac);
145a9643ea8Slogwang 	if (error)
146a9643ea8Slogwang 		return (error);
147a9643ea8Slogwang 
148a9643ea8Slogwang 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
149a9643ea8Slogwang 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
150a9643ea8Slogwang 	if (error) {
151a9643ea8Slogwang 		free(elements, M_MACTEMP);
152a9643ea8Slogwang 		return (error);
153a9643ea8Slogwang 	}
154a9643ea8Slogwang 
155a9643ea8Slogwang 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
156a9643ea8Slogwang 	error = mac_cred_externalize_label(td->td_ucred->cr_label,
157a9643ea8Slogwang 	    elements, buffer, mac.m_buflen);
158a9643ea8Slogwang 	if (error == 0)
159a9643ea8Slogwang 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
160a9643ea8Slogwang 
161a9643ea8Slogwang 	free(buffer, M_MACTEMP);
162a9643ea8Slogwang 	free(elements, M_MACTEMP);
163a9643ea8Slogwang 	return (error);
164a9643ea8Slogwang }
165a9643ea8Slogwang 
166a9643ea8Slogwang int
sys___mac_set_proc(struct thread * td,struct __mac_set_proc_args * uap)167a9643ea8Slogwang sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
168a9643ea8Slogwang {
169a9643ea8Slogwang 	struct ucred *newcred, *oldcred;
170a9643ea8Slogwang 	struct label *intlabel;
171a9643ea8Slogwang 	struct proc *p;
172a9643ea8Slogwang 	struct mac mac;
173a9643ea8Slogwang 	char *buffer;
174a9643ea8Slogwang 	int error;
175a9643ea8Slogwang 
176a9643ea8Slogwang 	if (!(mac_labeled & MPC_OBJECT_CRED))
177a9643ea8Slogwang 		return (EINVAL);
178a9643ea8Slogwang 
179a9643ea8Slogwang 	error = copyin(uap->mac_p, &mac, sizeof(mac));
180a9643ea8Slogwang 	if (error)
181a9643ea8Slogwang 		return (error);
182a9643ea8Slogwang 
183a9643ea8Slogwang 	error = mac_check_structmac_consistent(&mac);
184a9643ea8Slogwang 	if (error)
185a9643ea8Slogwang 		return (error);
186a9643ea8Slogwang 
187a9643ea8Slogwang 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
188a9643ea8Slogwang 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
189a9643ea8Slogwang 	if (error) {
190a9643ea8Slogwang 		free(buffer, M_MACTEMP);
191a9643ea8Slogwang 		return (error);
192a9643ea8Slogwang 	}
193a9643ea8Slogwang 
194a9643ea8Slogwang 	intlabel = mac_cred_label_alloc();
195a9643ea8Slogwang 	error = mac_cred_internalize_label(intlabel, buffer);
196a9643ea8Slogwang 	free(buffer, M_MACTEMP);
197a9643ea8Slogwang 	if (error)
198a9643ea8Slogwang 		goto out;
199a9643ea8Slogwang 
200a9643ea8Slogwang 	newcred = crget();
201a9643ea8Slogwang 
202a9643ea8Slogwang 	p = td->td_proc;
203a9643ea8Slogwang 	PROC_LOCK(p);
204a9643ea8Slogwang 	oldcred = p->p_ucred;
205a9643ea8Slogwang 
206a9643ea8Slogwang 	error = mac_cred_check_relabel(oldcred, intlabel);
207a9643ea8Slogwang 	if (error) {
208a9643ea8Slogwang 		PROC_UNLOCK(p);
209a9643ea8Slogwang 		crfree(newcred);
210a9643ea8Slogwang 		goto out;
211a9643ea8Slogwang 	}
212a9643ea8Slogwang 
213a9643ea8Slogwang 	setsugid(p);
214a9643ea8Slogwang 	crcopy(newcred, oldcred);
215a9643ea8Slogwang 	mac_cred_relabel(newcred, intlabel);
216a9643ea8Slogwang 	proc_set_cred(p, newcred);
217a9643ea8Slogwang 
218a9643ea8Slogwang 	PROC_UNLOCK(p);
219a9643ea8Slogwang 	crfree(oldcred);
220a9643ea8Slogwang 	mac_proc_vm_revoke(td);
221a9643ea8Slogwang 
222a9643ea8Slogwang out:
223a9643ea8Slogwang 	mac_cred_label_free(intlabel);
224a9643ea8Slogwang 	return (error);
225a9643ea8Slogwang }
226a9643ea8Slogwang 
227a9643ea8Slogwang int
sys___mac_get_fd(struct thread * td,struct __mac_get_fd_args * uap)228a9643ea8Slogwang sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
229a9643ea8Slogwang {
230a9643ea8Slogwang 	char *elements, *buffer;
231a9643ea8Slogwang 	struct label *intlabel;
232a9643ea8Slogwang 	struct file *fp;
233a9643ea8Slogwang 	struct mac mac;
234a9643ea8Slogwang 	struct vnode *vp;
235a9643ea8Slogwang 	struct pipe *pipe;
236a9643ea8Slogwang 	struct socket *so;
237a9643ea8Slogwang 	cap_rights_t rights;
238a9643ea8Slogwang 	int error;
239a9643ea8Slogwang 
240a9643ea8Slogwang 	error = copyin(uap->mac_p, &mac, sizeof(mac));
241a9643ea8Slogwang 	if (error)
242a9643ea8Slogwang 		return (error);
243a9643ea8Slogwang 
244a9643ea8Slogwang 	error = mac_check_structmac_consistent(&mac);
245a9643ea8Slogwang 	if (error)
246a9643ea8Slogwang 		return (error);
247a9643ea8Slogwang 
248a9643ea8Slogwang 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
249a9643ea8Slogwang 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
250a9643ea8Slogwang 	if (error) {
251a9643ea8Slogwang 		free(elements, M_MACTEMP);
252a9643ea8Slogwang 		return (error);
253a9643ea8Slogwang 	}
254a9643ea8Slogwang 
255a9643ea8Slogwang 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
256*22ce4affSfengbojiang 	error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_GET),
257*22ce4affSfengbojiang 	    &fp);
258a9643ea8Slogwang 	if (error)
259a9643ea8Slogwang 		goto out;
260a9643ea8Slogwang 
261a9643ea8Slogwang 	switch (fp->f_type) {
262a9643ea8Slogwang 	case DTYPE_FIFO:
263a9643ea8Slogwang 	case DTYPE_VNODE:
264a9643ea8Slogwang 		if (!(mac_labeled & MPC_OBJECT_VNODE)) {
265a9643ea8Slogwang 			error = EINVAL;
266a9643ea8Slogwang 			goto out_fdrop;
267a9643ea8Slogwang 		}
268a9643ea8Slogwang 		vp = fp->f_vnode;
269a9643ea8Slogwang 		intlabel = mac_vnode_label_alloc();
270a9643ea8Slogwang 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
271a9643ea8Slogwang 		mac_vnode_copy_label(vp->v_label, intlabel);
272*22ce4affSfengbojiang 		VOP_UNLOCK(vp);
273a9643ea8Slogwang 		error = mac_vnode_externalize_label(intlabel, elements,
274a9643ea8Slogwang 		    buffer, mac.m_buflen);
275a9643ea8Slogwang 		mac_vnode_label_free(intlabel);
276a9643ea8Slogwang 		break;
277a9643ea8Slogwang 
278a9643ea8Slogwang 	case DTYPE_PIPE:
279a9643ea8Slogwang 		if (!(mac_labeled & MPC_OBJECT_PIPE)) {
280a9643ea8Slogwang 			error = EINVAL;
281a9643ea8Slogwang 			goto out_fdrop;
282a9643ea8Slogwang 		}
283a9643ea8Slogwang 		pipe = fp->f_data;
284a9643ea8Slogwang 		intlabel = mac_pipe_label_alloc();
285a9643ea8Slogwang 		PIPE_LOCK(pipe);
286a9643ea8Slogwang 		mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
287a9643ea8Slogwang 		PIPE_UNLOCK(pipe);
288a9643ea8Slogwang 		error = mac_pipe_externalize_label(intlabel, elements,
289a9643ea8Slogwang 		    buffer, mac.m_buflen);
290a9643ea8Slogwang 		mac_pipe_label_free(intlabel);
291a9643ea8Slogwang 		break;
292a9643ea8Slogwang 
293a9643ea8Slogwang 	case DTYPE_SOCKET:
294a9643ea8Slogwang 		if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
295a9643ea8Slogwang 			error = EINVAL;
296a9643ea8Slogwang 			goto out_fdrop;
297a9643ea8Slogwang 		}
298a9643ea8Slogwang 		so = fp->f_data;
299a9643ea8Slogwang 		intlabel = mac_socket_label_alloc(M_WAITOK);
300a9643ea8Slogwang 		SOCK_LOCK(so);
301a9643ea8Slogwang 		mac_socket_copy_label(so->so_label, intlabel);
302a9643ea8Slogwang 		SOCK_UNLOCK(so);
303a9643ea8Slogwang 		error = mac_socket_externalize_label(intlabel, elements,
304a9643ea8Slogwang 		    buffer, mac.m_buflen);
305a9643ea8Slogwang 		mac_socket_label_free(intlabel);
306a9643ea8Slogwang 		break;
307a9643ea8Slogwang 
308a9643ea8Slogwang 	default:
309a9643ea8Slogwang 		error = EINVAL;
310a9643ea8Slogwang 	}
311a9643ea8Slogwang 	if (error == 0)
312a9643ea8Slogwang 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
313a9643ea8Slogwang out_fdrop:
314a9643ea8Slogwang 	fdrop(fp, td);
315a9643ea8Slogwang out:
316a9643ea8Slogwang 	free(buffer, M_MACTEMP);
317a9643ea8Slogwang 	free(elements, M_MACTEMP);
318a9643ea8Slogwang 	return (error);
319a9643ea8Slogwang }
320a9643ea8Slogwang 
321a9643ea8Slogwang int
sys___mac_get_file(struct thread * td,struct __mac_get_file_args * uap)322a9643ea8Slogwang sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
323a9643ea8Slogwang {
324a9643ea8Slogwang 
325*22ce4affSfengbojiang 	return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW));
326a9643ea8Slogwang }
327a9643ea8Slogwang 
328a9643ea8Slogwang int
sys___mac_get_link(struct thread * td,struct __mac_get_link_args * uap)329a9643ea8Slogwang sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
330a9643ea8Slogwang {
331*22ce4affSfengbojiang 
332*22ce4affSfengbojiang 	return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
333*22ce4affSfengbojiang }
334*22ce4affSfengbojiang 
335*22ce4affSfengbojiang static int
kern___mac_get_path(struct thread * td,const char * path_p,struct mac * mac_p,int follow)336*22ce4affSfengbojiang kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p,
337*22ce4affSfengbojiang    int follow)
338*22ce4affSfengbojiang {
339a9643ea8Slogwang 	char *elements, *buffer;
340a9643ea8Slogwang 	struct nameidata nd;
341a9643ea8Slogwang 	struct label *intlabel;
342a9643ea8Slogwang 	struct mac mac;
343a9643ea8Slogwang 	int error;
344a9643ea8Slogwang 
345a9643ea8Slogwang 	if (!(mac_labeled & MPC_OBJECT_VNODE))
346a9643ea8Slogwang 		return (EINVAL);
347a9643ea8Slogwang 
348*22ce4affSfengbojiang 	error = copyin(mac_p, &mac, sizeof(mac));
349a9643ea8Slogwang 	if (error)
350a9643ea8Slogwang 		return (error);
351a9643ea8Slogwang 
352a9643ea8Slogwang 	error = mac_check_structmac_consistent(&mac);
353a9643ea8Slogwang 	if (error)
354a9643ea8Slogwang 		return (error);
355a9643ea8Slogwang 
356a9643ea8Slogwang 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
357a9643ea8Slogwang 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
358a9643ea8Slogwang 	if (error) {
359a9643ea8Slogwang 		free(elements, M_MACTEMP);
360a9643ea8Slogwang 		return (error);
361a9643ea8Slogwang 	}
362a9643ea8Slogwang 
363a9643ea8Slogwang 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
364*22ce4affSfengbojiang 	NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p, td);
365a9643ea8Slogwang 	error = namei(&nd);
366a9643ea8Slogwang 	if (error)
367a9643ea8Slogwang 		goto out;
368a9643ea8Slogwang 
369a9643ea8Slogwang 	intlabel = mac_vnode_label_alloc();
370a9643ea8Slogwang 	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
371a9643ea8Slogwang 	error = mac_vnode_externalize_label(intlabel, elements, buffer,
372a9643ea8Slogwang 	    mac.m_buflen);
373a9643ea8Slogwang 	NDFREE(&nd, 0);
374a9643ea8Slogwang 	mac_vnode_label_free(intlabel);
375a9643ea8Slogwang 
376a9643ea8Slogwang 	if (error == 0)
377a9643ea8Slogwang 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
378a9643ea8Slogwang 
379a9643ea8Slogwang out:
380a9643ea8Slogwang 	free(buffer, M_MACTEMP);
381a9643ea8Slogwang 	free(elements, M_MACTEMP);
382a9643ea8Slogwang 
383a9643ea8Slogwang 	return (error);
384a9643ea8Slogwang }
385a9643ea8Slogwang 
386a9643ea8Slogwang int
sys___mac_set_fd(struct thread * td,struct __mac_set_fd_args * uap)387a9643ea8Slogwang sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
388a9643ea8Slogwang {
389a9643ea8Slogwang 	struct label *intlabel;
390a9643ea8Slogwang 	struct pipe *pipe;
391a9643ea8Slogwang 	struct socket *so;
392a9643ea8Slogwang 	struct file *fp;
393a9643ea8Slogwang 	struct mount *mp;
394a9643ea8Slogwang 	struct vnode *vp;
395a9643ea8Slogwang 	struct mac mac;
396a9643ea8Slogwang 	cap_rights_t rights;
397a9643ea8Slogwang 	char *buffer;
398a9643ea8Slogwang 	int error;
399a9643ea8Slogwang 
400a9643ea8Slogwang 	error = copyin(uap->mac_p, &mac, sizeof(mac));
401a9643ea8Slogwang 	if (error)
402a9643ea8Slogwang 		return (error);
403a9643ea8Slogwang 
404a9643ea8Slogwang 	error = mac_check_structmac_consistent(&mac);
405a9643ea8Slogwang 	if (error)
406a9643ea8Slogwang 		return (error);
407a9643ea8Slogwang 
408a9643ea8Slogwang 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
409a9643ea8Slogwang 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
410a9643ea8Slogwang 	if (error) {
411a9643ea8Slogwang 		free(buffer, M_MACTEMP);
412a9643ea8Slogwang 		return (error);
413a9643ea8Slogwang 	}
414a9643ea8Slogwang 
415*22ce4affSfengbojiang 	error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_SET),
416*22ce4affSfengbojiang 	    &fp);
417a9643ea8Slogwang 	if (error)
418a9643ea8Slogwang 		goto out;
419a9643ea8Slogwang 
420a9643ea8Slogwang 	switch (fp->f_type) {
421a9643ea8Slogwang 	case DTYPE_FIFO:
422a9643ea8Slogwang 	case DTYPE_VNODE:
423a9643ea8Slogwang 		if (!(mac_labeled & MPC_OBJECT_VNODE)) {
424a9643ea8Slogwang 			error = EINVAL;
425a9643ea8Slogwang 			goto out_fdrop;
426a9643ea8Slogwang 		}
427a9643ea8Slogwang 		intlabel = mac_vnode_label_alloc();
428a9643ea8Slogwang 		error = mac_vnode_internalize_label(intlabel, buffer);
429a9643ea8Slogwang 		if (error) {
430a9643ea8Slogwang 			mac_vnode_label_free(intlabel);
431a9643ea8Slogwang 			break;
432a9643ea8Slogwang 		}
433a9643ea8Slogwang 		vp = fp->f_vnode;
434a9643ea8Slogwang 		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
435a9643ea8Slogwang 		if (error != 0) {
436a9643ea8Slogwang 			mac_vnode_label_free(intlabel);
437a9643ea8Slogwang 			break;
438a9643ea8Slogwang 		}
439a9643ea8Slogwang 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
440a9643ea8Slogwang 		error = vn_setlabel(vp, intlabel, td->td_ucred);
441*22ce4affSfengbojiang 		VOP_UNLOCK(vp);
442a9643ea8Slogwang 		vn_finished_write(mp);
443a9643ea8Slogwang 		mac_vnode_label_free(intlabel);
444a9643ea8Slogwang 		break;
445a9643ea8Slogwang 
446a9643ea8Slogwang 	case DTYPE_PIPE:
447a9643ea8Slogwang 		if (!(mac_labeled & MPC_OBJECT_PIPE)) {
448a9643ea8Slogwang 			error = EINVAL;
449a9643ea8Slogwang 			goto out_fdrop;
450a9643ea8Slogwang 		}
451a9643ea8Slogwang 		intlabel = mac_pipe_label_alloc();
452a9643ea8Slogwang 		error = mac_pipe_internalize_label(intlabel, buffer);
453a9643ea8Slogwang 		if (error == 0) {
454a9643ea8Slogwang 			pipe = fp->f_data;
455a9643ea8Slogwang 			PIPE_LOCK(pipe);
456a9643ea8Slogwang 			error = mac_pipe_label_set(td->td_ucred,
457a9643ea8Slogwang 			    pipe->pipe_pair, intlabel);
458a9643ea8Slogwang 			PIPE_UNLOCK(pipe);
459a9643ea8Slogwang 		}
460a9643ea8Slogwang 		mac_pipe_label_free(intlabel);
461a9643ea8Slogwang 		break;
462a9643ea8Slogwang 
463a9643ea8Slogwang 	case DTYPE_SOCKET:
464a9643ea8Slogwang 		if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
465a9643ea8Slogwang 			error = EINVAL;
466a9643ea8Slogwang 			goto out_fdrop;
467a9643ea8Slogwang 		}
468a9643ea8Slogwang 		intlabel = mac_socket_label_alloc(M_WAITOK);
469a9643ea8Slogwang 		error = mac_socket_internalize_label(intlabel, buffer);
470a9643ea8Slogwang 		if (error == 0) {
471a9643ea8Slogwang 			so = fp->f_data;
472a9643ea8Slogwang 			error = mac_socket_label_set(td->td_ucred, so,
473a9643ea8Slogwang 			    intlabel);
474a9643ea8Slogwang 		}
475a9643ea8Slogwang 		mac_socket_label_free(intlabel);
476a9643ea8Slogwang 		break;
477a9643ea8Slogwang 
478a9643ea8Slogwang 	default:
479a9643ea8Slogwang 		error = EINVAL;
480a9643ea8Slogwang 	}
481a9643ea8Slogwang out_fdrop:
482a9643ea8Slogwang 	fdrop(fp, td);
483a9643ea8Slogwang out:
484a9643ea8Slogwang 	free(buffer, M_MACTEMP);
485a9643ea8Slogwang 	return (error);
486a9643ea8Slogwang }
487a9643ea8Slogwang 
488a9643ea8Slogwang int
sys___mac_set_file(struct thread * td,struct __mac_set_file_args * uap)489a9643ea8Slogwang sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
490a9643ea8Slogwang {
491a9643ea8Slogwang 
492*22ce4affSfengbojiang 	return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW));
493a9643ea8Slogwang }
494a9643ea8Slogwang 
495a9643ea8Slogwang int
sys___mac_set_link(struct thread * td,struct __mac_set_link_args * uap)496a9643ea8Slogwang sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
497a9643ea8Slogwang {
498*22ce4affSfengbojiang 
499*22ce4affSfengbojiang 	return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
500*22ce4affSfengbojiang }
501*22ce4affSfengbojiang 
502*22ce4affSfengbojiang static int
kern___mac_set_path(struct thread * td,const char * path_p,struct mac * mac_p,int follow)503*22ce4affSfengbojiang kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p,
504*22ce4affSfengbojiang     int follow)
505*22ce4affSfengbojiang {
506a9643ea8Slogwang 	struct label *intlabel;
507a9643ea8Slogwang 	struct nameidata nd;
508a9643ea8Slogwang 	struct mount *mp;
509a9643ea8Slogwang 	struct mac mac;
510a9643ea8Slogwang 	char *buffer;
511a9643ea8Slogwang 	int error;
512a9643ea8Slogwang 
513a9643ea8Slogwang 	if (!(mac_labeled & MPC_OBJECT_VNODE))
514a9643ea8Slogwang 		return (EINVAL);
515a9643ea8Slogwang 
516*22ce4affSfengbojiang 	error = copyin(mac_p, &mac, sizeof(mac));
517a9643ea8Slogwang 	if (error)
518a9643ea8Slogwang 		return (error);
519a9643ea8Slogwang 
520a9643ea8Slogwang 	error = mac_check_structmac_consistent(&mac);
521a9643ea8Slogwang 	if (error)
522a9643ea8Slogwang 		return (error);
523a9643ea8Slogwang 
524a9643ea8Slogwang 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
525a9643ea8Slogwang 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
526a9643ea8Slogwang 	if (error) {
527a9643ea8Slogwang 		free(buffer, M_MACTEMP);
528a9643ea8Slogwang 		return (error);
529a9643ea8Slogwang 	}
530a9643ea8Slogwang 
531a9643ea8Slogwang 	intlabel = mac_vnode_label_alloc();
532a9643ea8Slogwang 	error = mac_vnode_internalize_label(intlabel, buffer);
533a9643ea8Slogwang 	free(buffer, M_MACTEMP);
534a9643ea8Slogwang 	if (error)
535a9643ea8Slogwang 		goto out;
536a9643ea8Slogwang 
537*22ce4affSfengbojiang 	NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p, td);
538a9643ea8Slogwang 	error = namei(&nd);
539a9643ea8Slogwang 	if (error == 0) {
540a9643ea8Slogwang 		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
541a9643ea8Slogwang 		if (error == 0) {
542a9643ea8Slogwang 			error = vn_setlabel(nd.ni_vp, intlabel,
543a9643ea8Slogwang 			    td->td_ucred);
544a9643ea8Slogwang 			vn_finished_write(mp);
545a9643ea8Slogwang 		}
546a9643ea8Slogwang 	}
547a9643ea8Slogwang 
548a9643ea8Slogwang 	NDFREE(&nd, 0);
549a9643ea8Slogwang out:
550a9643ea8Slogwang 	mac_vnode_label_free(intlabel);
551a9643ea8Slogwang 	return (error);
552a9643ea8Slogwang }
553a9643ea8Slogwang 
554a9643ea8Slogwang int
sys_mac_syscall(struct thread * td,struct mac_syscall_args * uap)555a9643ea8Slogwang sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
556a9643ea8Slogwang {
557a9643ea8Slogwang 	struct mac_policy_conf *mpc;
558a9643ea8Slogwang 	char target[MAC_MAX_POLICY_NAME];
559a9643ea8Slogwang 	int error;
560a9643ea8Slogwang 
561a9643ea8Slogwang 	error = copyinstr(uap->policy, target, sizeof(target), NULL);
562a9643ea8Slogwang 	if (error)
563a9643ea8Slogwang 		return (error);
564a9643ea8Slogwang 
565a9643ea8Slogwang 	error = ENOSYS;
566a9643ea8Slogwang 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
567a9643ea8Slogwang 		if (strcmp(mpc->mpc_name, target) == 0 &&
568a9643ea8Slogwang 		    mpc->mpc_ops->mpo_syscall != NULL) {
569a9643ea8Slogwang 			error = mpc->mpc_ops->mpo_syscall(td,
570a9643ea8Slogwang 			    uap->call, uap->arg);
571a9643ea8Slogwang 			goto out;
572a9643ea8Slogwang 		}
573a9643ea8Slogwang 	}
574a9643ea8Slogwang 
575a9643ea8Slogwang 	if (!LIST_EMPTY(&mac_policy_list)) {
576a9643ea8Slogwang 		mac_policy_slock_sleep();
577a9643ea8Slogwang 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
578a9643ea8Slogwang 			if (strcmp(mpc->mpc_name, target) == 0 &&
579a9643ea8Slogwang 			    mpc->mpc_ops->mpo_syscall != NULL) {
580a9643ea8Slogwang 				error = mpc->mpc_ops->mpo_syscall(td,
581a9643ea8Slogwang 				    uap->call, uap->arg);
582a9643ea8Slogwang 				break;
583a9643ea8Slogwang 			}
584a9643ea8Slogwang 		}
585a9643ea8Slogwang 		mac_policy_sunlock_sleep();
586a9643ea8Slogwang 	}
587a9643ea8Slogwang out:
588a9643ea8Slogwang 	return (error);
589a9643ea8Slogwang }
590a9643ea8Slogwang 
591a9643ea8Slogwang #else /* !MAC */
592a9643ea8Slogwang 
593a9643ea8Slogwang int
sys___mac_get_pid(struct thread * td,struct __mac_get_pid_args * uap)594a9643ea8Slogwang sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
595a9643ea8Slogwang {
596a9643ea8Slogwang 
597a9643ea8Slogwang 	return (ENOSYS);
598a9643ea8Slogwang }
599a9643ea8Slogwang 
600a9643ea8Slogwang int
sys___mac_get_proc(struct thread * td,struct __mac_get_proc_args * uap)601a9643ea8Slogwang sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
602a9643ea8Slogwang {
603a9643ea8Slogwang 
604a9643ea8Slogwang 	return (ENOSYS);
605a9643ea8Slogwang }
606a9643ea8Slogwang 
607a9643ea8Slogwang int
sys___mac_set_proc(struct thread * td,struct __mac_set_proc_args * uap)608a9643ea8Slogwang sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
609a9643ea8Slogwang {
610a9643ea8Slogwang 
611a9643ea8Slogwang 	return (ENOSYS);
612a9643ea8Slogwang }
613a9643ea8Slogwang 
614a9643ea8Slogwang int
sys___mac_get_fd(struct thread * td,struct __mac_get_fd_args * uap)615a9643ea8Slogwang sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
616a9643ea8Slogwang {
617a9643ea8Slogwang 
618a9643ea8Slogwang 	return (ENOSYS);
619a9643ea8Slogwang }
620a9643ea8Slogwang 
621a9643ea8Slogwang int
sys___mac_get_file(struct thread * td,struct __mac_get_file_args * uap)622a9643ea8Slogwang sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
623a9643ea8Slogwang {
624a9643ea8Slogwang 
625a9643ea8Slogwang 	return (ENOSYS);
626a9643ea8Slogwang }
627a9643ea8Slogwang 
628a9643ea8Slogwang int
sys___mac_get_link(struct thread * td,struct __mac_get_link_args * uap)629a9643ea8Slogwang sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
630a9643ea8Slogwang {
631a9643ea8Slogwang 
632a9643ea8Slogwang 	return (ENOSYS);
633a9643ea8Slogwang }
634a9643ea8Slogwang 
635a9643ea8Slogwang int
sys___mac_set_fd(struct thread * td,struct __mac_set_fd_args * uap)636a9643ea8Slogwang sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
637a9643ea8Slogwang {
638a9643ea8Slogwang 
639a9643ea8Slogwang 	return (ENOSYS);
640a9643ea8Slogwang }
641a9643ea8Slogwang 
642a9643ea8Slogwang int
sys___mac_set_file(struct thread * td,struct __mac_set_file_args * uap)643a9643ea8Slogwang sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
644a9643ea8Slogwang {
645a9643ea8Slogwang 
646a9643ea8Slogwang 	return (ENOSYS);
647a9643ea8Slogwang }
648a9643ea8Slogwang 
649a9643ea8Slogwang int
sys___mac_set_link(struct thread * td,struct __mac_set_link_args * uap)650a9643ea8Slogwang sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
651a9643ea8Slogwang {
652a9643ea8Slogwang 
653a9643ea8Slogwang 	return (ENOSYS);
654a9643ea8Slogwang }
655a9643ea8Slogwang 
656a9643ea8Slogwang int
sys_mac_syscall(struct thread * td,struct mac_syscall_args * uap)657a9643ea8Slogwang sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
658a9643ea8Slogwang {
659a9643ea8Slogwang 
660a9643ea8Slogwang 	return (ENOSYS);
661a9643ea8Slogwang }
662a9643ea8Slogwang 
663a9643ea8Slogwang #endif /* !MAC */
664