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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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