18c7327e1SRobert Watson /*- 2212ab0cfSRobert Watson * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson 3f6a41092SRobert Watson * Copyright (c) 2001-2002 Networks Associates Technology, Inc. 430d239bcSRobert Watson * Copyright (c) 2006 SPARTA, Inc. 56356dba0SRobert Watson * Copyright (c) 2008 Apple Inc. 68c7327e1SRobert Watson * All rights reserved. 78c7327e1SRobert Watson * 88c7327e1SRobert Watson * This software was developed by Robert Watson for the TrustedBSD Project. 98c7327e1SRobert Watson * 10dc858fcaSRobert Watson * This software was developed for the FreeBSD Project in part by Network 11dc858fcaSRobert Watson * Associates Laboratories, the Security Research Division of Network 12dc858fcaSRobert Watson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 13dc858fcaSRobert Watson * as part of the DARPA CHATS research program. 148c7327e1SRobert Watson * 1530d239bcSRobert Watson * This software was enhanced by SPARTA ISSO under SPAWAR contract 1630d239bcSRobert Watson * N66001-04-C-6019 ("SEFOS"). 1730d239bcSRobert Watson * 188c7327e1SRobert Watson * Redistribution and use in source and binary forms, with or without 198c7327e1SRobert Watson * modification, are permitted provided that the following conditions 208c7327e1SRobert Watson * are met: 218c7327e1SRobert Watson * 1. Redistributions of source code must retain the above copyright 228c7327e1SRobert Watson * notice, this list of conditions and the following disclaimer. 238c7327e1SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 248c7327e1SRobert Watson * notice, this list of conditions and the following disclaimer in the 258c7327e1SRobert Watson * documentation and/or other materials provided with the distribution. 268c7327e1SRobert Watson * 278c7327e1SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 288c7327e1SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 298c7327e1SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 308c7327e1SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 318c7327e1SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 328c7327e1SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 338c7327e1SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 348c7327e1SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 358c7327e1SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 368c7327e1SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 378c7327e1SRobert Watson * SUCH DAMAGE. 388c7327e1SRobert Watson */ 398c7327e1SRobert Watson 408c7327e1SRobert Watson /* 418c7327e1SRobert Watson * Developed by the TrustedBSD Project. 423f1a7a90SRobert Watson * 438c7327e1SRobert Watson * Experiment with a partition-like model. 448c7327e1SRobert Watson */ 458c7327e1SRobert Watson 468c7327e1SRobert Watson #include <sys/param.h> 478c7327e1SRobert Watson #include <sys/kernel.h> 487405fcc3SRobert Watson #include <sys/module.h> 49acd3428bSRobert Watson #include <sys/priv.h> 508c7327e1SRobert Watson #include <sys/proc.h> 51f51e5803SRobert Watson #include <sys/sbuf.h> 527fb179baSBjoern A. Zeeb #include <sys/socket.h> 534a5216a6SBjoern A. Zeeb #include <sys/socketvar.h> 548c7327e1SRobert Watson #include <sys/systm.h> 558c7327e1SRobert Watson #include <sys/sysctl.h> 568c7327e1SRobert Watson 577fb179baSBjoern A. Zeeb #include <net/route.h> 587fb179baSBjoern A. Zeeb #include <netinet/in.h> 597fb179baSBjoern A. Zeeb #include <netinet/in_pcb.h> 607fb179baSBjoern A. Zeeb 610efd6615SRobert Watson #include <security/mac/mac_policy.h> 628c7327e1SRobert Watson #include <security/mac_partition/mac_partition.h> 638c7327e1SRobert Watson 64*7029da5cSPawel Biernacki static SYSCTL_NODE(_security_mac, OID_AUTO, partition, 65*7029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 668c7327e1SRobert Watson "TrustedBSD mac_partition policy controls"); 678c7327e1SRobert Watson 68f7c4bd95SRobert Watson static int partition_enabled = 1; 698c7327e1SRobert Watson SYSCTL_INT(_security_mac_partition, OID_AUTO, enabled, CTLFLAG_RW, 70f7c4bd95SRobert Watson &partition_enabled, 0, "Enforce partition policy"); 718c7327e1SRobert Watson 728c7327e1SRobert Watson static int partition_slot; 730142affcSRobert Watson #define SLOT(l) mac_label_get((l), partition_slot) 740142affcSRobert Watson #define SLOT_SET(l, v) mac_label_set((l), partition_slot, (v)) 758c7327e1SRobert Watson 768c7327e1SRobert Watson static int 776c6c03beSRobert Watson partition_check(struct label *subject, struct label *object) 788c7327e1SRobert Watson { 798c7327e1SRobert Watson 80f7c4bd95SRobert Watson if (partition_enabled == 0) 818c7327e1SRobert Watson return (0); 828c7327e1SRobert Watson 836356dba0SRobert Watson if (subject == NULL) 846356dba0SRobert Watson return (0); 856356dba0SRobert Watson 868c7327e1SRobert Watson if (SLOT(subject) == 0) 878c7327e1SRobert Watson return (0); 888c7327e1SRobert Watson 896356dba0SRobert Watson /* 906356dba0SRobert Watson * If the object label hasn't been allocated, then it's effectively 916356dba0SRobert Watson * not in a partition, and we know the subject is as it has a label 926356dba0SRobert Watson * and it's not 0, so reject. 936356dba0SRobert Watson */ 946356dba0SRobert Watson if (object == NULL) 956356dba0SRobert Watson return (EPERM); 966356dba0SRobert Watson 978c7327e1SRobert Watson if (SLOT(subject) == SLOT(object)) 988c7327e1SRobert Watson return (0); 998c7327e1SRobert Watson 1008c7327e1SRobert Watson return (EPERM); 1018c7327e1SRobert Watson } 1028c7327e1SRobert Watson 103eb320b0eSRobert Watson /* 104eb320b0eSRobert Watson * Object-specific entry points are sorted alphabetically by object type name 105eb320b0eSRobert Watson * and then by operation. 106eb320b0eSRobert Watson */ 1078c7327e1SRobert Watson static int 1083f1a7a90SRobert Watson partition_cred_check_relabel(struct ucred *cred, struct label *newlabel) 1098c7327e1SRobert Watson { 1108c7327e1SRobert Watson int error; 1118c7327e1SRobert Watson 1128c7327e1SRobert Watson error = 0; 1138c7327e1SRobert Watson 114048e2d58SRobert Watson /* 115048e2d58SRobert Watson * Treat "0" as a no-op request because it reflects an unset 116048e2d58SRobert Watson * partition label. If we ever want to support switching back to an 117048e2d58SRobert Watson * unpartitioned state for a process, we'll need to differentiate the 118048e2d58SRobert Watson * "not in a partition" and "no partition defined during internalize" 119048e2d58SRobert Watson * conditions. 120048e2d58SRobert Watson */ 1218c7327e1SRobert Watson if (SLOT(newlabel) != 0) { 1228c7327e1SRobert Watson /* 1230d89ccd7SRobert Watson * Require BSD privilege in order to change the partition. 1243f1a7a90SRobert Watson * Originally we also required that the process not be in a 1253f1a7a90SRobert Watson * partition in the first place, but this didn't interact 1263f1a7a90SRobert Watson * well with sendmail. 1278c7327e1SRobert Watson */ 128cc426dd3SMateusz Guzik error = priv_check_cred(cred, PRIV_MAC_PARTITION); 1298c7327e1SRobert Watson } 1308c7327e1SRobert Watson 1318c7327e1SRobert Watson return (error); 1328c7327e1SRobert Watson } 1338c7327e1SRobert Watson 1348c7327e1SRobert Watson static int 1353f1a7a90SRobert Watson partition_cred_check_visible(struct ucred *cr1, struct ucred *cr2) 1368c7327e1SRobert Watson { 1378c7327e1SRobert Watson int error; 1388c7327e1SRobert Watson 1396c6c03beSRobert Watson error = partition_check(cr1->cr_label, cr2->cr_label); 1408c7327e1SRobert Watson 1418c7327e1SRobert Watson return (error == 0 ? 0 : ESRCH); 1428c7327e1SRobert Watson } 1438c7327e1SRobert Watson 144eb320b0eSRobert Watson static void 145eb320b0eSRobert Watson partition_cred_copy_label(struct label *src, struct label *dest) 146eb320b0eSRobert Watson { 147eb320b0eSRobert Watson 1486356dba0SRobert Watson if (src != NULL && dest != NULL) 149eb320b0eSRobert Watson SLOT_SET(dest, SLOT(src)); 1506356dba0SRobert Watson else if (dest != NULL) 1516356dba0SRobert Watson SLOT_SET(dest, 0); 152eb320b0eSRobert Watson } 153eb320b0eSRobert Watson 154eb320b0eSRobert Watson static void 155212ab0cfSRobert Watson partition_cred_create_init(struct ucred *cred) 156212ab0cfSRobert Watson { 157212ab0cfSRobert Watson 158212ab0cfSRobert Watson SLOT_SET(cred->cr_label, 0); 159212ab0cfSRobert Watson } 160212ab0cfSRobert Watson 161212ab0cfSRobert Watson static void 162212ab0cfSRobert Watson partition_cred_create_swapper(struct ucred *cred) 163212ab0cfSRobert Watson { 164212ab0cfSRobert Watson 165212ab0cfSRobert Watson SLOT_SET(cred->cr_label, 0); 166212ab0cfSRobert Watson } 167212ab0cfSRobert Watson 168212ab0cfSRobert Watson static void 169eb320b0eSRobert Watson partition_cred_destroy_label(struct label *label) 170eb320b0eSRobert Watson { 171eb320b0eSRobert Watson 172eb320b0eSRobert Watson SLOT_SET(label, 0); 173eb320b0eSRobert Watson } 174eb320b0eSRobert Watson 175eb320b0eSRobert Watson static int 176eb320b0eSRobert Watson partition_cred_externalize_label(struct label *label, char *element_name, 177eb320b0eSRobert Watson struct sbuf *sb, int *claimed) 178eb320b0eSRobert Watson { 179eb320b0eSRobert Watson 180eb320b0eSRobert Watson if (strcmp(MAC_PARTITION_LABEL_NAME, element_name) != 0) 181eb320b0eSRobert Watson return (0); 182eb320b0eSRobert Watson 183eb320b0eSRobert Watson (*claimed)++; 184eb320b0eSRobert Watson 1856356dba0SRobert Watson if (label != NULL) { 186eb320b0eSRobert Watson if (sbuf_printf(sb, "%jd", (intmax_t)SLOT(label)) == -1) 187eb320b0eSRobert Watson return (EINVAL); 1886356dba0SRobert Watson } else { 1896356dba0SRobert Watson if (sbuf_printf(sb, "0") == -1) 1906356dba0SRobert Watson return (EINVAL); 1916356dba0SRobert Watson } 192eb320b0eSRobert Watson return (0); 193eb320b0eSRobert Watson } 194eb320b0eSRobert Watson 195eb320b0eSRobert Watson static void 196eb320b0eSRobert Watson partition_cred_init_label(struct label *label) 197eb320b0eSRobert Watson { 198eb320b0eSRobert Watson 199eb320b0eSRobert Watson SLOT_SET(label, 0); 200eb320b0eSRobert Watson } 201eb320b0eSRobert Watson 202eb320b0eSRobert Watson static int 203eb320b0eSRobert Watson partition_cred_internalize_label(struct label *label, char *element_name, 204eb320b0eSRobert Watson char *element_data, int *claimed) 205eb320b0eSRobert Watson { 206eb320b0eSRobert Watson 207eb320b0eSRobert Watson if (strcmp(MAC_PARTITION_LABEL_NAME, element_name) != 0) 208eb320b0eSRobert Watson return (0); 209eb320b0eSRobert Watson 210eb320b0eSRobert Watson (*claimed)++; 211eb320b0eSRobert Watson SLOT_SET(label, strtol(element_data, NULL, 10)); 212eb320b0eSRobert Watson return (0); 213eb320b0eSRobert Watson } 214eb320b0eSRobert Watson 215eb320b0eSRobert Watson static void 216eb320b0eSRobert Watson partition_cred_relabel(struct ucred *cred, struct label *newlabel) 217eb320b0eSRobert Watson { 218eb320b0eSRobert Watson 2196356dba0SRobert Watson if (newlabel != NULL && SLOT(newlabel) != 0) 220eb320b0eSRobert Watson SLOT_SET(cred->cr_label, SLOT(newlabel)); 221eb320b0eSRobert Watson } 222eb320b0eSRobert Watson 2238c7327e1SRobert Watson static int 2247fb179baSBjoern A. Zeeb partition_inpcb_check_visible(struct ucred *cred, struct inpcb *inp, 2257fb179baSBjoern A. Zeeb struct label *inplabel) 2267fb179baSBjoern A. Zeeb { 2277fb179baSBjoern A. Zeeb int error; 2287fb179baSBjoern A. Zeeb 2296c6c03beSRobert Watson error = partition_check(cred->cr_label, inp->inp_cred->cr_label); 2307fb179baSBjoern A. Zeeb 2317fb179baSBjoern A. Zeeb return (error ? ENOENT : 0); 2327fb179baSBjoern A. Zeeb } 2337fb179baSBjoern A. Zeeb 2347fb179baSBjoern A. Zeeb static int 2353f1a7a90SRobert Watson partition_proc_check_debug(struct ucred *cred, struct proc *p) 2368c7327e1SRobert Watson { 2378c7327e1SRobert Watson int error; 2388c7327e1SRobert Watson 2396c6c03beSRobert Watson error = partition_check(cred->cr_label, p->p_ucred->cr_label); 2408c7327e1SRobert Watson 2418c7327e1SRobert Watson return (error ? ESRCH : 0); 2428c7327e1SRobert Watson } 2438c7327e1SRobert Watson 2448c7327e1SRobert Watson static int 2453f1a7a90SRobert Watson partition_proc_check_sched(struct ucred *cred, struct proc *p) 2468c7327e1SRobert Watson { 2478c7327e1SRobert Watson int error; 2488c7327e1SRobert Watson 2496c6c03beSRobert Watson error = partition_check(cred->cr_label, p->p_ucred->cr_label); 2508c7327e1SRobert Watson 2518c7327e1SRobert Watson return (error ? ESRCH : 0); 2528c7327e1SRobert Watson } 2538c7327e1SRobert Watson 2548c7327e1SRobert Watson static int 2553f1a7a90SRobert Watson partition_proc_check_signal(struct ucred *cred, struct proc *p, 2568c7327e1SRobert Watson int signum) 2578c7327e1SRobert Watson { 2588c7327e1SRobert Watson int error; 2598c7327e1SRobert Watson 2606c6c03beSRobert Watson error = partition_check(cred->cr_label, p->p_ucred->cr_label); 2618c7327e1SRobert Watson 2628c7327e1SRobert Watson return (error ? ESRCH : 0); 2638c7327e1SRobert Watson } 2648c7327e1SRobert Watson 2658c7327e1SRobert Watson static int 2663f1a7a90SRobert Watson partition_socket_check_visible(struct ucred *cred, struct socket *so, 26778007886SRobert Watson struct label *solabel) 2688c7327e1SRobert Watson { 2698c7327e1SRobert Watson int error; 2708c7327e1SRobert Watson 2716c6c03beSRobert Watson error = partition_check(cred->cr_label, so->so_cred->cr_label); 2728c7327e1SRobert Watson 2738c7327e1SRobert Watson return (error ? ENOENT : 0); 2748c7327e1SRobert Watson } 2758c7327e1SRobert Watson 276ef5def59SRobert Watson static int 2773f1a7a90SRobert Watson partition_vnode_check_exec(struct ucred *cred, struct vnode *vp, 27878007886SRobert Watson struct label *vplabel, struct image_params *imgp, 27978007886SRobert Watson struct label *execlabel) 280ef5def59SRobert Watson { 281ef5def59SRobert Watson 282ef5def59SRobert Watson if (execlabel != NULL) { 283ef5def59SRobert Watson /* 284ef5def59SRobert Watson * We currently don't permit labels to be changed at 285ef5def59SRobert Watson * exec-time as part of the partition model, so disallow 286ef5def59SRobert Watson * non-NULL partition label changes in execlabel. 287ef5def59SRobert Watson */ 288ef5def59SRobert Watson if (SLOT(execlabel) != 0) 289ef5def59SRobert Watson return (EINVAL); 290ef5def59SRobert Watson } 291ef5def59SRobert Watson 292ef5def59SRobert Watson return (0); 293ef5def59SRobert Watson } 294ef5def59SRobert Watson 2953f1a7a90SRobert Watson static struct mac_policy_ops partition_ops = 2968c7327e1SRobert Watson { 2973f1a7a90SRobert Watson .mpo_cred_check_relabel = partition_cred_check_relabel, 2983f1a7a90SRobert Watson .mpo_cred_check_visible = partition_cred_check_visible, 299eb320b0eSRobert Watson .mpo_cred_copy_label = partition_cred_copy_label, 300212ab0cfSRobert Watson .mpo_cred_create_init = partition_cred_create_init, 301212ab0cfSRobert Watson .mpo_cred_create_swapper = partition_cred_create_swapper, 302eb320b0eSRobert Watson .mpo_cred_destroy_label = partition_cred_destroy_label, 303eb320b0eSRobert Watson .mpo_cred_externalize_label = partition_cred_externalize_label, 304eb320b0eSRobert Watson .mpo_cred_init_label = partition_cred_init_label, 305eb320b0eSRobert Watson .mpo_cred_internalize_label = partition_cred_internalize_label, 306eb320b0eSRobert Watson .mpo_cred_relabel = partition_cred_relabel, 3077fb179baSBjoern A. Zeeb .mpo_inpcb_check_visible = partition_inpcb_check_visible, 3083f1a7a90SRobert Watson .mpo_proc_check_debug = partition_proc_check_debug, 3093f1a7a90SRobert Watson .mpo_proc_check_sched = partition_proc_check_sched, 3103f1a7a90SRobert Watson .mpo_proc_check_signal = partition_proc_check_signal, 3113f1a7a90SRobert Watson .mpo_socket_check_visible = partition_socket_check_visible, 3123f1a7a90SRobert Watson .mpo_vnode_check_exec = partition_vnode_check_exec, 3138c7327e1SRobert Watson }; 3148c7327e1SRobert Watson 3153f1a7a90SRobert Watson MAC_POLICY_SET(&partition_ops, mac_partition, "TrustedBSD MAC/Partition", 3169162f64bSRobert Watson MPC_LOADTIME_FLAG_UNLOADOK, &partition_slot); 317