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>
467bc82500SRobert Watson #include "opt_mac.h"
47f9d0d524SRobert Watson
487bc82500SRobert Watson #include <sys/param.h>
49*3bdc5ba2SOlivier Certner #include <sys/abi_compat.h>
504a144410SRobert Watson #include <sys/capsicum.h>
5157b4252eSKonstantin Belousov #include <sys/fcntl.h>
5295fab37eSRobert Watson #include <sys/kernel.h>
5395fab37eSRobert Watson #include <sys/lock.h>
54b656366bSBruce Evans #include <sys/malloc.h>
5595fab37eSRobert Watson #include <sys/mutex.h>
5695fab37eSRobert Watson #include <sys/mac.h>
5795fab37eSRobert Watson #include <sys/proc.h>
5895fab37eSRobert Watson #include <sys/systm.h>
59de5b1952SAlexander Leidinger #include <sys/sysctl.h>
607bc82500SRobert Watson #include <sys/sysproto.h>
6195fab37eSRobert Watson #include <sys/vnode.h>
6295fab37eSRobert Watson #include <sys/mount.h>
6395fab37eSRobert Watson #include <sys/file.h>
6495fab37eSRobert Watson #include <sys/namei.h>
6595fab37eSRobert Watson #include <sys/socket.h>
6695fab37eSRobert Watson #include <sys/pipe.h>
6795fab37eSRobert Watson #include <sys/socketvar.h>
6895fab37eSRobert Watson
69aed55708SRobert Watson #include <security/mac/mac_framework.h>
706fa0475dSRobert Watson #include <security/mac/mac_internal.h>
710efd6615SRobert Watson #include <security/mac/mac_policy.h>
728a4d24a3SOlivier Certner #include <security/mac/mac_syscalls.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
83*3bdc5ba2SOlivier Certner #ifdef COMPAT_FREEBSD32
84*3bdc5ba2SOlivier Certner struct mac32 {
85*3bdc5ba2SOlivier Certner uint32_t m_buflen; /* size_t */
86*3bdc5ba2SOlivier Certner uint32_t m_string; /* char * */
87*3bdc5ba2SOlivier Certner };
88*3bdc5ba2SOlivier Certner #endif
89*3bdc5ba2SOlivier Certner
902e593dd3SOlivier Certner /*
912e593dd3SOlivier Certner * Copyin a 'struct mac', including the string pointed to by 'm_string'.
922e593dd3SOlivier Certner *
932e593dd3SOlivier Certner * On success (0 returned), fills '*mac', whose associated storage must be freed
942e593dd3SOlivier Certner * after use by calling free_copied_label() (which see). On success, 'u_string'
952e593dd3SOlivier Certner * if not NULL is filled with the userspace address for 'u_mac->m_string'.
962e593dd3SOlivier Certner */
97*3bdc5ba2SOlivier Certner static int
mac_label_copyin_impl(const void * const u_mac,struct mac * const mac,char ** const u_string,bool is_32bit)98*3bdc5ba2SOlivier Certner mac_label_copyin_impl(const void *const u_mac, struct mac *const mac,
99*3bdc5ba2SOlivier Certner char **const u_string, bool is_32bit)
1002e593dd3SOlivier Certner {
1012e593dd3SOlivier Certner char *buffer;
1022e593dd3SOlivier Certner int error;
1032e593dd3SOlivier Certner
104*3bdc5ba2SOlivier Certner #ifdef COMPAT_FREEBSD32
105*3bdc5ba2SOlivier Certner if (is_32bit) {
106*3bdc5ba2SOlivier Certner struct mac32 mac32;
107*3bdc5ba2SOlivier Certner
108*3bdc5ba2SOlivier Certner error = copyin(u_mac, &mac32, sizeof(mac32));
109*3bdc5ba2SOlivier Certner if (error != 0)
110*3bdc5ba2SOlivier Certner return (error);
111*3bdc5ba2SOlivier Certner
112*3bdc5ba2SOlivier Certner CP(mac32, *mac, m_buflen);
113*3bdc5ba2SOlivier Certner PTRIN_CP(mac32, *mac, m_string);
114*3bdc5ba2SOlivier Certner } else
115*3bdc5ba2SOlivier Certner #endif
116*3bdc5ba2SOlivier Certner {
1172e593dd3SOlivier Certner error = copyin(u_mac, mac, sizeof(*mac));
1182e593dd3SOlivier Certner if (error != 0)
1192e593dd3SOlivier Certner return (error);
120*3bdc5ba2SOlivier Certner }
1212e593dd3SOlivier Certner
1222e593dd3SOlivier Certner error = mac_check_structmac_consistent(mac);
1232e593dd3SOlivier Certner if (error != 0)
1242e593dd3SOlivier Certner return (error);
1252e593dd3SOlivier Certner
1262e593dd3SOlivier Certner /* 'm_buflen' not too big checked by function call above. */
1272e593dd3SOlivier Certner buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
1282e593dd3SOlivier Certner error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
1292e593dd3SOlivier Certner if (error != 0) {
1302e593dd3SOlivier Certner free(buffer, M_MACTEMP);
1312e593dd3SOlivier Certner return (error);
1322e593dd3SOlivier Certner }
1332e593dd3SOlivier Certner
1342e593dd3SOlivier Certner MPASS(error == 0);
1352e593dd3SOlivier Certner if (u_string != NULL)
1362e593dd3SOlivier Certner *u_string = mac->m_string;
1372e593dd3SOlivier Certner mac->m_string = buffer;
1382e593dd3SOlivier Certner return (0);
1392e593dd3SOlivier Certner }
1402e593dd3SOlivier Certner
141*3bdc5ba2SOlivier Certner int
mac_label_copyin(const struct mac * const u_mac,struct mac * const mac,char ** const u_string)142*3bdc5ba2SOlivier Certner mac_label_copyin(const struct mac *const u_mac, struct mac *const mac,
143*3bdc5ba2SOlivier Certner char **const u_string)
144*3bdc5ba2SOlivier Certner {
145*3bdc5ba2SOlivier Certner return (mac_label_copyin_impl(u_mac, mac, u_string, false));
146*3bdc5ba2SOlivier Certner }
147*3bdc5ba2SOlivier Certner
1488a4d24a3SOlivier Certner void
free_copied_label(const struct mac * const mac)1492e593dd3SOlivier Certner free_copied_label(const struct mac *const mac)
1502e593dd3SOlivier Certner {
1512e593dd3SOlivier Certner free(mac->m_string, M_MACTEMP);
1522e593dd3SOlivier Certner }
1532e593dd3SOlivier Certner
154*3bdc5ba2SOlivier Certner #ifdef COMPAT_FREEBSD32
155*3bdc5ba2SOlivier Certner int
mac_label_copyin32(const struct mac32 * const u_mac,struct mac * const mac,char ** const u_string)156*3bdc5ba2SOlivier Certner mac_label_copyin32(const struct mac32 *const u_mac,
157*3bdc5ba2SOlivier Certner struct mac *const mac, char **const u_string)
158*3bdc5ba2SOlivier Certner {
159*3bdc5ba2SOlivier Certner return (mac_label_copyin_impl(u_mac, mac, u_string, true));
160*3bdc5ba2SOlivier Certner }
161*3bdc5ba2SOlivier Certner #endif
162*3bdc5ba2SOlivier Certner
163f7b951a8SRobert Watson int
sys___mac_get_pid(struct thread * td,struct __mac_get_pid_args * uap)1648451d0ddSKip Macy sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
165f7b951a8SRobert Watson {
1662e593dd3SOlivier Certner char *buffer, *u_buffer;
167f7b951a8SRobert Watson struct mac mac;
168f7b951a8SRobert Watson struct proc *tproc;
169f7b951a8SRobert Watson struct ucred *tcred;
170f7b951a8SRobert Watson int error;
171f7b951a8SRobert Watson
1722e593dd3SOlivier Certner error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
173f7b951a8SRobert Watson if (error)
174f7b951a8SRobert Watson return (error);
175f7b951a8SRobert Watson
176f7b951a8SRobert Watson tproc = pfind(uap->pid);
1772e593dd3SOlivier Certner if (tproc == NULL) {
1782e593dd3SOlivier Certner error = ESRCH;
1792e593dd3SOlivier Certner goto free_mac_and_exit;
1802e593dd3SOlivier Certner }
181f7b951a8SRobert Watson
182f7b951a8SRobert Watson tcred = NULL; /* Satisfy gcc. */
183f7b951a8SRobert Watson error = p_cansee(td, tproc);
184f7b951a8SRobert Watson if (error == 0)
185f7b951a8SRobert Watson tcred = crhold(tproc->p_ucred);
186f7b951a8SRobert Watson PROC_UNLOCK(tproc);
187f7b951a8SRobert Watson if (error)
1882e593dd3SOlivier Certner goto free_mac_and_exit;
189f7b951a8SRobert Watson
190a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1912e593dd3SOlivier Certner error = mac_cred_externalize_label(tcred->cr_label, mac.m_string,
19283b7b0edSRobert Watson buffer, mac.m_buflen);
193f7b951a8SRobert Watson if (error == 0)
1942e593dd3SOlivier Certner error = copyout(buffer, u_buffer, strlen(buffer)+1);
195f7b951a8SRobert Watson free(buffer, M_MACTEMP);
196f7b951a8SRobert Watson crfree(tcred);
1972e593dd3SOlivier Certner
1982e593dd3SOlivier Certner free_mac_and_exit:
1992e593dd3SOlivier Certner free_copied_label(&mac);
200f7b951a8SRobert Watson return (error);
201f7b951a8SRobert Watson }
202f7b951a8SRobert Watson
20395fab37eSRobert Watson int
sys___mac_get_proc(struct thread * td,struct __mac_get_proc_args * uap)2048451d0ddSKip Macy sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
20595fab37eSRobert Watson {
2062e593dd3SOlivier Certner char *buffer, *u_buffer;
207f7b951a8SRobert Watson struct mac mac;
20895fab37eSRobert Watson int error;
20995fab37eSRobert Watson
2102e593dd3SOlivier Certner error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
211f7b951a8SRobert Watson if (error)
212f7b951a8SRobert Watson return (error);
21395fab37eSRobert Watson
214a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
21530d239bcSRobert Watson error = mac_cred_externalize_label(td->td_ucred->cr_label,
2162e593dd3SOlivier Certner mac.m_string, buffer, mac.m_buflen);
217f7b951a8SRobert Watson if (error == 0)
2182e593dd3SOlivier Certner error = copyout(buffer, u_buffer, strlen(buffer)+1);
219f7b951a8SRobert Watson
220f7b951a8SRobert Watson free(buffer, M_MACTEMP);
2212e593dd3SOlivier Certner free_copied_label(&mac);
22295fab37eSRobert Watson return (error);
22395fab37eSRobert Watson }
22495fab37eSRobert Watson
2258a4d24a3SOlivier Certner /*
2268a4d24a3SOlivier Certner * Performs preparation (including allocations) for mac_set_proc().
2278a4d24a3SOlivier Certner *
2288a4d24a3SOlivier Certner * No lock should be held while calling this function. On success,
2298a4d24a3SOlivier Certner * mac_set_proc_finish() must be called to free the data associated to
2308a4d24a3SOlivier Certner * 'mac_set_proc_data', even if mac_set_proc_core() fails. 'mac_set_proc_data'
2318a4d24a3SOlivier Certner * is not set in case of error, and is set to a non-NULL value on success.
2328a4d24a3SOlivier Certner */
2338a4d24a3SOlivier Certner int
mac_set_proc_prepare(struct thread * const td,const struct mac * const mac,void ** const mac_set_proc_data)2348a4d24a3SOlivier Certner mac_set_proc_prepare(struct thread *const td, const struct mac *const mac,
2358a4d24a3SOlivier Certner void **const mac_set_proc_data)
2368a4d24a3SOlivier Certner {
2378a4d24a3SOlivier Certner struct label *intlabel;
2388a4d24a3SOlivier Certner int error;
2398a4d24a3SOlivier Certner
2408a4d24a3SOlivier Certner PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
2418a4d24a3SOlivier Certner
2428a4d24a3SOlivier Certner if (!(mac_labeled & MPC_OBJECT_CRED))
2438a4d24a3SOlivier Certner return (EINVAL);
2448a4d24a3SOlivier Certner
2458a4d24a3SOlivier Certner intlabel = mac_cred_label_alloc();
2468a4d24a3SOlivier Certner error = mac_cred_internalize_label(intlabel, mac->m_string);
2478a4d24a3SOlivier Certner if (error) {
2488a4d24a3SOlivier Certner mac_cred_label_free(intlabel);
2498a4d24a3SOlivier Certner return (error);
2508a4d24a3SOlivier Certner }
2518a4d24a3SOlivier Certner
2528a4d24a3SOlivier Certner *mac_set_proc_data = intlabel;
2538a4d24a3SOlivier Certner return (0);
2548a4d24a3SOlivier Certner }
2558a4d24a3SOlivier Certner
2568a4d24a3SOlivier Certner /*
2578a4d24a3SOlivier Certner * Actually sets the MAC label on 'newcred'.
2588a4d24a3SOlivier Certner *
2598a4d24a3SOlivier Certner * The current process' lock *must* be held. This function only sets the label
2608a4d24a3SOlivier Certner * on 'newcred', but does not put 'newcred' in place on the current process'
2618a4d24a3SOlivier Certner * (consequently, it also does not call setsugid()). 'mac_set_proc_data' must
2628a4d24a3SOlivier Certner * be the pointer returned by mac_set_proc_prepare(). If called, this function
2638a4d24a3SOlivier Certner * must be so between a successful call to mac_set_proc_prepare() and
2648a4d24a3SOlivier Certner * mac_set_proc_finish(), but calling it is not mandatory (e.g., if some other
2658a4d24a3SOlivier Certner * error occured under the process lock that obsoletes setting the MAC label).
2668a4d24a3SOlivier Certner */
2678a4d24a3SOlivier Certner int
mac_set_proc_core(struct thread * const td,struct ucred * const newcred,void * const mac_set_proc_data)2688a4d24a3SOlivier Certner mac_set_proc_core(struct thread *const td, struct ucred *const newcred,
2698a4d24a3SOlivier Certner void *const mac_set_proc_data)
2708a4d24a3SOlivier Certner {
2718a4d24a3SOlivier Certner struct label *const intlabel = mac_set_proc_data;
2728a4d24a3SOlivier Certner struct proc *const p = td->td_proc;
2738a4d24a3SOlivier Certner int error;
2748a4d24a3SOlivier Certner
2758a4d24a3SOlivier Certner MPASS(td == curthread);
2768a4d24a3SOlivier Certner PROC_LOCK_ASSERT(p, MA_OWNED);
2778a4d24a3SOlivier Certner
2788a4d24a3SOlivier Certner error = mac_cred_check_relabel(p->p_ucred, intlabel);
2798a4d24a3SOlivier Certner if (error)
2808a4d24a3SOlivier Certner return (error);
2818a4d24a3SOlivier Certner
2828a4d24a3SOlivier Certner mac_cred_relabel(newcred, intlabel);
2838a4d24a3SOlivier Certner return (0);
2848a4d24a3SOlivier Certner }
2858a4d24a3SOlivier Certner
2868a4d24a3SOlivier Certner /*
2878a4d24a3SOlivier Certner * Performs mac_set_proc() last operations, without the process lock.
2888a4d24a3SOlivier Certner *
2898a4d24a3SOlivier Certner * 'proc_label_set' indicates whether the label was actually set by a call to
2908a4d24a3SOlivier Certner * mac_set_proc_core() that succeeded. 'mac_set_proc_data' must be the pointer
2918a4d24a3SOlivier Certner * returned by mac_set_proc_prepare(), and its associated data will be freed.
2928a4d24a3SOlivier Certner */
2938a4d24a3SOlivier Certner void
mac_set_proc_finish(struct thread * const td,bool proc_label_set,void * const mac_set_proc_data)2948a4d24a3SOlivier Certner mac_set_proc_finish(struct thread *const td, bool proc_label_set,
2958a4d24a3SOlivier Certner void *const mac_set_proc_data)
2968a4d24a3SOlivier Certner {
2978a4d24a3SOlivier Certner struct label *const intlabel = mac_set_proc_data;
2988a4d24a3SOlivier Certner
2998a4d24a3SOlivier Certner PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
3008a4d24a3SOlivier Certner
3018a4d24a3SOlivier Certner if (proc_label_set)
3028a4d24a3SOlivier Certner mac_proc_vm_revoke(td);
3038a4d24a3SOlivier Certner mac_cred_label_free(intlabel);
3048a4d24a3SOlivier Certner }
3058a4d24a3SOlivier Certner
30695fab37eSRobert Watson int
sys___mac_set_proc(struct thread * td,struct __mac_set_proc_args * uap)3078451d0ddSKip Macy sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
30895fab37eSRobert Watson {
30995fab37eSRobert Watson struct ucred *newcred, *oldcred;
3108a4d24a3SOlivier Certner void *intlabel;
3118a4d24a3SOlivier Certner struct proc *const p = td->td_proc;
312f7b951a8SRobert Watson struct mac mac;
31395fab37eSRobert Watson int error;
31495fab37eSRobert Watson
3152e593dd3SOlivier Certner error = mac_label_copyin(uap->mac_p, &mac, NULL);
31695fab37eSRobert Watson if (error)
31795fab37eSRobert Watson return (error);
31895fab37eSRobert Watson
3198a4d24a3SOlivier Certner error = mac_set_proc_prepare(td, &mac, &intlabel);
320eca8a663SRobert Watson if (error)
3218a4d24a3SOlivier Certner goto free_label;
322f7b951a8SRobert Watson
32395fab37eSRobert Watson newcred = crget();
32495fab37eSRobert Watson
32595fab37eSRobert Watson PROC_LOCK(p);
32695fab37eSRobert Watson oldcred = p->p_ucred;
3278a4d24a3SOlivier Certner crcopy(newcred, oldcred);
32895fab37eSRobert Watson
3298a4d24a3SOlivier Certner error = mac_set_proc_core(td, newcred, intlabel);
33095fab37eSRobert Watson if (error) {
33195fab37eSRobert Watson PROC_UNLOCK(p);
33295fab37eSRobert Watson crfree(newcred);
3338a4d24a3SOlivier Certner goto finish;
33495fab37eSRobert Watson }
33595fab37eSRobert Watson
33695fab37eSRobert Watson setsugid(p);
337daf63fd2SMateusz Guzik proc_set_cred(p, newcred);
33895fab37eSRobert Watson PROC_UNLOCK(p);
339f7b951a8SRobert Watson
3408a4d24a3SOlivier Certner crfree(oldcred);
3418a4d24a3SOlivier Certner finish:
3428a4d24a3SOlivier Certner mac_set_proc_finish(td, error == 0, intlabel);
3438a4d24a3SOlivier Certner free_label:
3448a4d24a3SOlivier Certner free_copied_label(&mac);
345f7b951a8SRobert Watson return (error);
34695fab37eSRobert Watson }
34795fab37eSRobert Watson
34895fab37eSRobert Watson int
sys___mac_get_fd(struct thread * td,struct __mac_get_fd_args * uap)3498451d0ddSKip Macy sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
35095fab37eSRobert Watson {
3512e593dd3SOlivier Certner char *u_buffer, *buffer;
352eca8a663SRobert Watson struct label *intlabel;
35395fab37eSRobert Watson struct file *fp;
354f7b951a8SRobert Watson struct mac mac;
35595fab37eSRobert Watson struct vnode *vp;
35695fab37eSRobert Watson struct pipe *pipe;
357b0323ea3SRobert Watson struct socket *so;
3587008be5bSPawel Jakub Dawidek cap_rights_t rights;
3595050aa86SKonstantin Belousov int error;
36095fab37eSRobert Watson
3612e593dd3SOlivier Certner error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
362f7b951a8SRobert Watson if (error)
363f7b951a8SRobert Watson return (error);
36495fab37eSRobert Watson
365a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
3666b3a9a0fSMateusz Guzik error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_GET),
3676b3a9a0fSMateusz Guzik &fp);
36895fab37eSRobert Watson if (error)
36995fab37eSRobert Watson goto out;
37095fab37eSRobert Watson
37195fab37eSRobert Watson switch (fp->f_type) {
37295fab37eSRobert Watson case DTYPE_FIFO:
37395fab37eSRobert Watson case DTYPE_VNODE:
374b4ef8be2SRobert Watson if (!(mac_labeled & MPC_OBJECT_VNODE)) {
375b4ef8be2SRobert Watson error = EINVAL;
376b4ef8be2SRobert Watson goto out_fdrop;
377b4ef8be2SRobert Watson }
3783b6d9652SPoul-Henning Kamp vp = fp->f_vnode;
379eca8a663SRobert Watson intlabel = mac_vnode_label_alloc();
380cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
38130d239bcSRobert Watson mac_vnode_copy_label(vp->v_label, intlabel);
382b249ce48SMateusz Guzik VOP_UNLOCK(vp);
3832e593dd3SOlivier Certner error = mac_vnode_externalize_label(intlabel, mac.m_string,
384f0ab0442SRobert Watson buffer, mac.m_buflen);
385f0ab0442SRobert Watson mac_vnode_label_free(intlabel);
38695fab37eSRobert Watson break;
387f0ab0442SRobert Watson
38895fab37eSRobert Watson case DTYPE_PIPE:
389b4ef8be2SRobert Watson if (!(mac_labeled & MPC_OBJECT_PIPE)) {
390b4ef8be2SRobert Watson error = EINVAL;
391b4ef8be2SRobert Watson goto out_fdrop;
392b4ef8be2SRobert Watson }
39348e3128bSMatthew Dillon pipe = fp->f_data;
394eca8a663SRobert Watson intlabel = mac_pipe_label_alloc();
395f7b951a8SRobert Watson PIPE_LOCK(pipe);
39630d239bcSRobert Watson mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
397f7b951a8SRobert Watson PIPE_UNLOCK(pipe);
3982e593dd3SOlivier Certner error = mac_pipe_externalize_label(intlabel, mac.m_string,
39983b7b0edSRobert Watson buffer, mac.m_buflen);
400eca8a663SRobert Watson mac_pipe_label_free(intlabel);
401f7b951a8SRobert Watson break;
40295fab37eSRobert Watson
403b0323ea3SRobert Watson case DTYPE_SOCKET:
404b4ef8be2SRobert Watson if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
405b4ef8be2SRobert Watson error = EINVAL;
406b4ef8be2SRobert Watson goto out_fdrop;
407b4ef8be2SRobert Watson }
408b0323ea3SRobert Watson so = fp->f_data;
409b0323ea3SRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK);
410f0c2044bSRobert Watson SOCK_LOCK(so);
41130d239bcSRobert Watson mac_socket_copy_label(so->so_label, intlabel);
412f0c2044bSRobert Watson SOCK_UNLOCK(so);
4132e593dd3SOlivier Certner error = mac_socket_externalize_label(intlabel, mac.m_string,
414b0323ea3SRobert Watson buffer, mac.m_buflen);
415b0323ea3SRobert Watson mac_socket_label_free(intlabel);
416b0323ea3SRobert Watson break;
417b0323ea3SRobert Watson
418f0ab0442SRobert Watson default:
419f0ab0442SRobert Watson error = EINVAL;
420f0ab0442SRobert Watson }
42195fab37eSRobert Watson if (error == 0)
4222e593dd3SOlivier Certner error = copyout(buffer, u_buffer, strlen(buffer)+1);
423b4ef8be2SRobert Watson out_fdrop:
424b4ef8be2SRobert Watson fdrop(fp, td);
42595fab37eSRobert Watson out:
426f7b951a8SRobert Watson free(buffer, M_MACTEMP);
4272e593dd3SOlivier Certner free_copied_label(&mac);
42895fab37eSRobert Watson return (error);
42995fab37eSRobert Watson }
43095fab37eSRobert Watson
43195fab37eSRobert Watson int
sys___mac_get_file(struct thread * td,struct __mac_get_file_args * uap)4328451d0ddSKip Macy sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
43395fab37eSRobert Watson {
43495fab37eSRobert Watson
435d88fe103SBrooks Davis return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW));
436f7b951a8SRobert Watson }
437f7b951a8SRobert Watson
438f7b951a8SRobert Watson int
sys___mac_get_link(struct thread * td,struct __mac_get_link_args * uap)4398451d0ddSKip Macy sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
440f7b951a8SRobert Watson {
441d88fe103SBrooks Davis
442d88fe103SBrooks Davis return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
443d88fe103SBrooks Davis }
444d88fe103SBrooks Davis
445d88fe103SBrooks Davis static int
kern___mac_get_path(struct thread * td,const char * path_p,struct mac * mac_p,int follow)446d88fe103SBrooks Davis kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p,
447d88fe103SBrooks Davis int follow)
448d88fe103SBrooks Davis {
4492e593dd3SOlivier Certner char *u_buffer, *buffer;
450f7b951a8SRobert Watson struct nameidata nd;
451eca8a663SRobert Watson struct label *intlabel;
452f7b951a8SRobert Watson struct mac mac;
4535050aa86SKonstantin Belousov int error;
454f7b951a8SRobert Watson
4556356dba0SRobert Watson if (!(mac_labeled & MPC_OBJECT_VNODE))
4566356dba0SRobert Watson return (EINVAL);
4576356dba0SRobert Watson
4582e593dd3SOlivier Certner error = mac_label_copyin(mac_p, &mac, &u_buffer);
459f7b951a8SRobert Watson if (error)
460f7b951a8SRobert Watson return (error);
461f7b951a8SRobert Watson
462a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
4637e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p);
464f7b951a8SRobert Watson error = namei(&nd);
46595fab37eSRobert Watson if (error)
46695fab37eSRobert Watson goto out;
46795fab37eSRobert Watson
468eca8a663SRobert Watson intlabel = mac_vnode_label_alloc();
46930d239bcSRobert Watson mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
4702e593dd3SOlivier Certner error = mac_vnode_externalize_label(intlabel, mac.m_string, buffer,
47183b7b0edSRobert Watson mac.m_buflen);
47285dac03eSMateusz Guzik vput(nd.ni_vp);
47385dac03eSMateusz Guzik NDFREE_PNBUF(&nd);
474eca8a663SRobert Watson mac_vnode_label_free(intlabel);
475f7b951a8SRobert Watson
476f7b951a8SRobert Watson if (error == 0)
4772e593dd3SOlivier Certner error = copyout(buffer, u_buffer, strlen(buffer)+1);
47895fab37eSRobert Watson
47995fab37eSRobert Watson out:
480f7b951a8SRobert Watson free(buffer, M_MACTEMP);
4812e593dd3SOlivier Certner free_copied_label(&mac);
482f7b951a8SRobert Watson
48395fab37eSRobert Watson return (error);
48495fab37eSRobert Watson }
48595fab37eSRobert Watson
48695fab37eSRobert Watson int
sys___mac_set_fd(struct thread * td,struct __mac_set_fd_args * uap)4878451d0ddSKip Macy sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
48895fab37eSRobert Watson {
489eca8a663SRobert Watson struct label *intlabel;
490f7b951a8SRobert Watson struct pipe *pipe;
491b0323ea3SRobert Watson struct socket *so;
492f7b951a8SRobert Watson struct file *fp;
49395fab37eSRobert Watson struct mount *mp;
49495fab37eSRobert Watson struct vnode *vp;
495f7b951a8SRobert Watson struct mac mac;
4967008be5bSPawel Jakub Dawidek cap_rights_t rights;
4975050aa86SKonstantin Belousov int error;
49895fab37eSRobert Watson
4992e593dd3SOlivier Certner error = mac_label_copyin(uap->mac_p, &mac, NULL);
500f7b951a8SRobert Watson if (error)
501f7b951a8SRobert Watson return (error);
502f7b951a8SRobert Watson
5036b3a9a0fSMateusz Guzik error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_SET),
5046b3a9a0fSMateusz Guzik &fp);
50595fab37eSRobert Watson if (error)
506f7b951a8SRobert Watson goto out;
50795fab37eSRobert Watson
50895fab37eSRobert Watson switch (fp->f_type) {
50995fab37eSRobert Watson case DTYPE_FIFO:
51095fab37eSRobert Watson case DTYPE_VNODE:
511b4ef8be2SRobert Watson if (!(mac_labeled & MPC_OBJECT_VNODE)) {
512b4ef8be2SRobert Watson error = EINVAL;
513b4ef8be2SRobert Watson goto out_fdrop;
514b4ef8be2SRobert Watson }
515eca8a663SRobert Watson intlabel = mac_vnode_label_alloc();
5162e593dd3SOlivier Certner error = mac_vnode_internalize_label(intlabel, mac.m_string);
517f7b951a8SRobert Watson if (error) {
518eca8a663SRobert Watson mac_vnode_label_free(intlabel);
519f7b951a8SRobert Watson break;
520f7b951a8SRobert Watson }
5213b6d9652SPoul-Henning Kamp vp = fp->f_vnode;
522a75d1dddSMateusz Guzik error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
523f7b951a8SRobert Watson if (error != 0) {
524eca8a663SRobert Watson mac_vnode_label_free(intlabel);
52595fab37eSRobert Watson break;
526f7b951a8SRobert Watson }
527cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
528eca8a663SRobert Watson error = vn_setlabel(vp, intlabel, td->td_ucred);
529b249ce48SMateusz Guzik VOP_UNLOCK(vp);
53095fab37eSRobert Watson vn_finished_write(mp);
531eca8a663SRobert Watson mac_vnode_label_free(intlabel);
53295fab37eSRobert Watson break;
533f7b951a8SRobert Watson
53495fab37eSRobert Watson case DTYPE_PIPE:
535b4ef8be2SRobert Watson if (!(mac_labeled & MPC_OBJECT_PIPE)) {
536b4ef8be2SRobert Watson error = EINVAL;
537b4ef8be2SRobert Watson goto out_fdrop;
538b4ef8be2SRobert Watson }
539eca8a663SRobert Watson intlabel = mac_pipe_label_alloc();
5402e593dd3SOlivier Certner error = mac_pipe_internalize_label(intlabel, mac.m_string);
541f7b951a8SRobert Watson if (error == 0) {
54248e3128bSMatthew Dillon pipe = fp->f_data;
5431aa37f53SRobert Watson PIPE_LOCK(pipe);
5444795b82cSRobert Watson error = mac_pipe_label_set(td->td_ucred,
5454795b82cSRobert Watson pipe->pipe_pair, intlabel);
5461aa37f53SRobert Watson PIPE_UNLOCK(pipe);
547f7b951a8SRobert Watson }
548eca8a663SRobert Watson mac_pipe_label_free(intlabel);
54995fab37eSRobert Watson break;
550f7b951a8SRobert Watson
551b0323ea3SRobert Watson case DTYPE_SOCKET:
552b4ef8be2SRobert Watson if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
553b4ef8be2SRobert Watson error = EINVAL;
554b4ef8be2SRobert Watson goto out_fdrop;
555b4ef8be2SRobert Watson }
556b0323ea3SRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK);
5572e593dd3SOlivier Certner error = mac_socket_internalize_label(intlabel, mac.m_string);
558b0323ea3SRobert Watson if (error == 0) {
559b0323ea3SRobert Watson so = fp->f_data;
560b0323ea3SRobert Watson error = mac_socket_label_set(td->td_ucred, so,
561b0323ea3SRobert Watson intlabel);
562b0323ea3SRobert Watson }
563b0323ea3SRobert Watson mac_socket_label_free(intlabel);
564b0323ea3SRobert Watson break;
565b0323ea3SRobert Watson
56695fab37eSRobert Watson default:
56795fab37eSRobert Watson error = EINVAL;
56895fab37eSRobert Watson }
569b4ef8be2SRobert Watson out_fdrop:
57095fab37eSRobert Watson fdrop(fp, td);
571f7b951a8SRobert Watson out:
5722e593dd3SOlivier Certner free_copied_label(&mac);
57395fab37eSRobert Watson return (error);
57495fab37eSRobert Watson }
57595fab37eSRobert Watson
57695fab37eSRobert Watson int
sys___mac_set_file(struct thread * td,struct __mac_set_file_args * uap)5778451d0ddSKip Macy sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
57895fab37eSRobert Watson {
57995fab37eSRobert Watson
580d88fe103SBrooks Davis return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW));
581f7b951a8SRobert Watson }
582f7b951a8SRobert Watson
583f7b951a8SRobert Watson int
sys___mac_set_link(struct thread * td,struct __mac_set_link_args * uap)5848451d0ddSKip Macy sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
585f7b951a8SRobert Watson {
586d88fe103SBrooks Davis
587d88fe103SBrooks Davis return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
588d88fe103SBrooks Davis }
589d88fe103SBrooks Davis
590d88fe103SBrooks Davis static int
kern___mac_set_path(struct thread * td,const char * path_p,struct mac * mac_p,int follow)591d88fe103SBrooks Davis kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p,
592d88fe103SBrooks Davis int follow)
593d88fe103SBrooks Davis {
594eca8a663SRobert Watson struct label *intlabel;
595f7b951a8SRobert Watson struct nameidata nd;
596f7b951a8SRobert Watson struct mount *mp;
597f7b951a8SRobert Watson struct mac mac;
5985050aa86SKonstantin Belousov int error;
599f7b951a8SRobert Watson
6006356dba0SRobert Watson if (!(mac_labeled & MPC_OBJECT_VNODE))
6016356dba0SRobert Watson return (EINVAL);
6026356dba0SRobert Watson
6032e593dd3SOlivier Certner error = mac_label_copyin(mac_p, &mac, NULL);
604f7b951a8SRobert Watson if (error)
605f7b951a8SRobert Watson return (error);
606f7b951a8SRobert Watson
607eca8a663SRobert Watson intlabel = mac_vnode_label_alloc();
6082e593dd3SOlivier Certner error = mac_vnode_internalize_label(intlabel, mac.m_string);
6092e593dd3SOlivier Certner free_copied_label(&mac);
610eca8a663SRobert Watson if (error)
611eca8a663SRobert Watson goto out;
612f7b951a8SRobert Watson
6137e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p);
614f7b951a8SRobert Watson error = namei(&nd);
615f7b951a8SRobert Watson if (error == 0) {
616a75d1dddSMateusz Guzik error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
617d50ef66dSTor Egge if (error == 0) {
618eca8a663SRobert Watson error = vn_setlabel(nd.ni_vp, intlabel,
619f7b951a8SRobert Watson td->td_ucred);
620f7b951a8SRobert Watson vn_finished_write(mp);
621f7b951a8SRobert Watson }
62285dac03eSMateusz Guzik vput(nd.ni_vp);
62385dac03eSMateusz Guzik NDFREE_PNBUF(&nd);
624d50ef66dSTor Egge }
625eca8a663SRobert Watson out:
626eca8a663SRobert Watson mac_vnode_label_free(intlabel);
627f7b951a8SRobert Watson return (error);
628f7b951a8SRobert Watson }
629f7b951a8SRobert Watson
63027f2eac7SRobert Watson int
sys_mac_syscall(struct thread * td,struct mac_syscall_args * uap)6318451d0ddSKip Macy sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
63227f2eac7SRobert Watson {
63327f2eac7SRobert Watson struct mac_policy_conf *mpc;
63427f2eac7SRobert Watson char target[MAC_MAX_POLICY_NAME];
63540202729SRobert Watson int error;
63627f2eac7SRobert Watson
637d1e405c5SAlfred Perlstein error = copyinstr(uap->policy, target, sizeof(target), NULL);
63827f2eac7SRobert Watson if (error)
63927f2eac7SRobert Watson return (error);
64027f2eac7SRobert Watson
64127f2eac7SRobert Watson error = ENOSYS;
642a6a65b05SRobert Watson LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
64327f2eac7SRobert Watson if (strcmp(mpc->mpc_name, target) == 0 &&
64427f2eac7SRobert Watson mpc->mpc_ops->mpo_syscall != NULL) {
64527f2eac7SRobert Watson error = mpc->mpc_ops->mpo_syscall(td,
646d1e405c5SAlfred Perlstein uap->call, uap->arg);
64727f2eac7SRobert Watson goto out;
64827f2eac7SRobert Watson }
64927f2eac7SRobert Watson }
65027f2eac7SRobert Watson
65140202729SRobert Watson if (!LIST_EMPTY(&mac_policy_list)) {
65240202729SRobert Watson mac_policy_slock_sleep();
65341a17fe3SRobert Watson LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
65441a17fe3SRobert Watson if (strcmp(mpc->mpc_name, target) == 0 &&
65541a17fe3SRobert Watson mpc->mpc_ops->mpo_syscall != NULL) {
65641a17fe3SRobert Watson error = mpc->mpc_ops->mpo_syscall(td,
65741a17fe3SRobert Watson uap->call, uap->arg);
65841a17fe3SRobert Watson break;
65941a17fe3SRobert Watson }
66041a17fe3SRobert Watson }
66140202729SRobert Watson mac_policy_sunlock_sleep();
66241a17fe3SRobert Watson }
66327f2eac7SRobert Watson out:
66427f2eac7SRobert Watson return (error);
66527f2eac7SRobert Watson }
66627f2eac7SRobert Watson
66795fab37eSRobert Watson #else /* !MAC */
6687bc82500SRobert Watson
6697bc82500SRobert Watson int
sys___mac_get_pid(struct thread * td,struct __mac_get_pid_args * uap)6708451d0ddSKip Macy sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
671f7b951a8SRobert Watson {
672f7b951a8SRobert Watson
673f7b951a8SRobert Watson return (ENOSYS);
674f7b951a8SRobert Watson }
675f7b951a8SRobert Watson
676f7b951a8SRobert Watson int
sys___mac_get_proc(struct thread * td,struct __mac_get_proc_args * uap)6778451d0ddSKip Macy sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
6787bc82500SRobert Watson {
6797bc82500SRobert Watson
6807bc82500SRobert Watson return (ENOSYS);
6817bc82500SRobert Watson }
6827bc82500SRobert Watson
6837bc82500SRobert Watson int
sys___mac_set_proc(struct thread * td,struct __mac_set_proc_args * uap)6848451d0ddSKip Macy sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
6857bc82500SRobert Watson {
6867bc82500SRobert Watson
6877bc82500SRobert Watson return (ENOSYS);
6887bc82500SRobert Watson }
6897bc82500SRobert Watson
6907bc82500SRobert Watson int
sys___mac_get_fd(struct thread * td,struct __mac_get_fd_args * uap)6918451d0ddSKip Macy sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
6927bc82500SRobert Watson {
6937bc82500SRobert Watson
6947bc82500SRobert Watson return (ENOSYS);
6957bc82500SRobert Watson }
6967bc82500SRobert Watson
6977bc82500SRobert Watson int
sys___mac_get_file(struct thread * td,struct __mac_get_file_args * uap)6988451d0ddSKip Macy sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
6997bc82500SRobert Watson {
7007bc82500SRobert Watson
7017bc82500SRobert Watson return (ENOSYS);
7027bc82500SRobert Watson }
7037bc82500SRobert Watson
7047bc82500SRobert Watson int
sys___mac_get_link(struct thread * td,struct __mac_get_link_args * uap)7058451d0ddSKip Macy sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
706f7b951a8SRobert Watson {
707f7b951a8SRobert Watson
708f7b951a8SRobert Watson return (ENOSYS);
709f7b951a8SRobert Watson }
710f7b951a8SRobert Watson
711f7b951a8SRobert Watson int
sys___mac_set_fd(struct thread * td,struct __mac_set_fd_args * uap)7128451d0ddSKip Macy sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
7137bc82500SRobert Watson {
7147bc82500SRobert Watson
7157bc82500SRobert Watson return (ENOSYS);
7167bc82500SRobert Watson }
7177bc82500SRobert Watson
7187bc82500SRobert Watson int
sys___mac_set_file(struct thread * td,struct __mac_set_file_args * uap)7198451d0ddSKip Macy sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
7207bc82500SRobert Watson {
7217bc82500SRobert Watson
7227bc82500SRobert Watson return (ENOSYS);
7237bc82500SRobert Watson }
72495fab37eSRobert Watson
72527f2eac7SRobert Watson int
sys___mac_set_link(struct thread * td,struct __mac_set_link_args * uap)7268451d0ddSKip Macy sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
727f7b951a8SRobert Watson {
728f7b951a8SRobert Watson
729f7b951a8SRobert Watson return (ENOSYS);
730f7b951a8SRobert Watson }
731f7b951a8SRobert Watson
732f7b951a8SRobert Watson int
sys_mac_syscall(struct thread * td,struct mac_syscall_args * uap)7338451d0ddSKip Macy sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
73427f2eac7SRobert Watson {
73527f2eac7SRobert Watson
73627f2eac7SRobert Watson return (ENOSYS);
73727f2eac7SRobert Watson }
73827f2eac7SRobert Watson
73919b78822SRobert Watson #endif /* !MAC */
740