1121054Semax/*- 2121054Semax * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson 3189462Semax * Copyright (c) 2001-2002 Networks Associates Technology, Inc. 4189462Semax * Copyright (c) 2006 SPARTA, Inc. 5189462Semax * Copyright (c) 2008 Apple Inc. 6189462Semax * All rights reserved. 7121054Semax * 8121054Semax * This software was developed by Robert Watson for the TrustedBSD Project. 9121054Semax * 10121054Semax * This software was developed for the FreeBSD Project in part by Network 11121054Semax * Associates Laboratories, the Security Research Division of Network 12121054Semax * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 13121054Semax * as part of the DARPA CHATS research program. 14121054Semax * 15121054Semax * This software was enhanced by SPARTA ISSO under SPAWAR contract 16121054Semax * N66001-04-C-6019 ("SEFOS"). 17121054Semax * 18121054Semax * Redistribution and use in source and binary forms, with or without 19121054Semax * modification, are permitted provided that the following conditions 20121054Semax * are met: 21121054Semax * 1. Redistributions of source code must retain the above copyright 22121054Semax * notice, this list of conditions and the following disclaimer. 23121054Semax * 2. Redistributions in binary form must reproduce the above copyright 24121054Semax * notice, this list of conditions and the following disclaimer in the 25121054Semax * documentation and/or other materials provided with the distribution. 26121054Semax * 27121054Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30121054Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 31121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37121054Semax * SUCH DAMAGE. 38121054Semax * 39121054Semax * $FreeBSD$ 40189462Semax */ 41121054Semax 42191388Semax/* 43121054Semax * Developed by the TrustedBSD Project. 44189462Semax * 45121054Semax * Experiment with a partition-like model. 46189462Semax */ 47121054Semax 48121054Semax#include <sys/param.h> 49121054Semax#include <sys/kernel.h> 50191388Semax#include <sys/module.h> 51121054Semax#include <sys/priv.h> 52121054Semax#include <sys/proc.h> 53121054Semax#include <sys/sbuf.h> 54121054Semax#include <sys/socket.h> 55143767Semax#include <sys/socketvar.h> 56121054Semax#include <sys/systm.h> 57121054Semax#include <sys/sysctl.h> 58121054Semax 59121054Semax#include <net/route.h> 60121054Semax#include <netinet/in.h> 61121054Semax#include <netinet/in_pcb.h> 62213042Semax 63213042Semax#include <security/mac/mac_policy.h> 64213042Semax#include <security/mac_partition/mac_partition.h> 65213042Semax 66121054SemaxSYSCTL_DECL(_security_mac); 67121054Semax 68121054Semaxstatic SYSCTL_NODE(_security_mac, OID_AUTO, partition, CTLFLAG_RW, 0, 69121054Semax "TrustedBSD mac_partition policy controls"); 70121054Semax 71121054Semaxstatic int partition_enabled = 1; 72121054SemaxSYSCTL_INT(_security_mac_partition, OID_AUTO, enabled, CTLFLAG_RW, 73121054Semax &partition_enabled, 0, "Enforce partition policy"); 74121054Semax 75121054Semaxstatic int partition_slot; 76121054Semax#define SLOT(l) mac_label_get((l), partition_slot) 77121054Semax#define SLOT_SET(l, v) mac_label_set((l), partition_slot, (v)) 78121054Semax 79121054Semaxstatic int 80121054Semaxpartition_check(struct label *subject, struct label *object) 81121054Semax{ 82121054Semax 83121054Semax if (partition_enabled == 0) 84121054Semax return (0); 85121054Semax 86189462Semax if (subject == NULL) 87189462Semax return (0); 88189462Semax 89189462Semax if (SLOT(subject) == 0) 90189462Semax return (0); 91189462Semax 92189462Semax /* 93189462Semax * If the object label hasn't been allocated, then it's effectively 94189462Semax * not in a partition, and we know the subject is as it has a label 95189462Semax * and it's not 0, so reject. 96189462Semax */ 97189462Semax if (object == NULL) 98189462Semax return (EPERM); 99189462Semax 100189462Semax if (SLOT(subject) == SLOT(object)) 101189462Semax return (0); 102189462Semax 103189462Semax return (EPERM); 104189462Semax} 105189462Semax 106189462Semax/* 107189462Semax * Object-specific entry points are sorted alphabetically by object type name 108189462Semax * and then by operation. 109189462Semax */ 110189462Semaxstatic int 111189462Semaxpartition_cred_check_relabel(struct ucred *cred, struct label *newlabel) 112189462Semax{ 113189462Semax int error; 114189462Semax 115189462Semax error = 0; 116189462Semax 117189462Semax /* 118189462Semax * Treat "0" as a no-op request because it reflects an unset 119189462Semax * partition label. If we ever want to support switching back to an 120189462Semax * unpartitioned state for a process, we'll need to differentiate the 121189462Semax * "not in a partition" and "no partition defined during internalize" 122189462Semax * conditions. 123189462Semax */ 124189462Semax if (SLOT(newlabel) != 0) { 125189462Semax /* 126189462Semax * Require BSD privilege in order to change the partition. 127189462Semax * Originally we also required that the process not be in a 128189462Semax * partition in the first place, but this didn't interact 129189462Semax * well with sendmail. 130189462Semax */ 131189462Semax error = priv_check_cred(cred, PRIV_MAC_PARTITION, 0); 132189462Semax } 133189462Semax 134189462Semax return (error); 135189462Semax} 136189462Semax 137189462Semaxstatic int 138191388Semaxpartition_cred_check_visible(struct ucred *cr1, struct ucred *cr2) 139191388Semax{ 140191388Semax int error; 141191388Semax 142191388Semax error = partition_check(cr1->cr_label, cr2->cr_label); 143191388Semax 144191388Semax return (error == 0 ? 0 : ESRCH); 145191388Semax} 146191388Semax 147191388Semaxstatic void 148191388Semaxpartition_cred_copy_label(struct label *src, struct label *dest) 149191388Semax{ 150191388Semax 151191388Semax if (src != NULL && dest != NULL) 152191388Semax SLOT_SET(dest, SLOT(src)); 153191388Semax else if (dest != NULL) 154191388Semax SLOT_SET(dest, 0); 155191388Semax} 156191388Semax 157191388Semaxstatic void 158191388Semaxpartition_cred_create_init(struct ucred *cred) 159191388Semax{ 160191388Semax 161191388Semax SLOT_SET(cred->cr_label, 0); 162191388Semax} 163189462Semax 164189462Semaxstatic void 165191388Semaxpartition_cred_create_swapper(struct ucred *cred) 166191388Semax{ 167191388Semax 168191388Semax SLOT_SET(cred->cr_label, 0); 169191388Semax} 170198492Semax 171198492Semaxstatic void 172191388Semaxpartition_cred_destroy_label(struct label *label) 173191388Semax{ 174191388Semax 175191388Semax SLOT_SET(label, 0); 176191388Semax} 177191388Semax 178191388Semaxstatic int 179191388Semaxpartition_cred_externalize_label(struct label *label, char *element_name, 180189462Semax struct sbuf *sb, int *claimed) 181189462Semax{ 182189462Semax 183181698Semax if (strcmp(MAC_PARTITION_LABEL_NAME, element_name) != 0) 184181698Semax return (0); 185181698Semax 186181698Semax (*claimed)++; 187181698Semax 188181698Semax if (label != NULL) { 189181698Semax if (sbuf_printf(sb, "%jd", (intmax_t)SLOT(label)) == -1) 190181698Semax return (EINVAL); 191181698Semax } else { 192181698Semax if (sbuf_printf(sb, "0") == -1) 193181698Semax return (EINVAL); 194181698Semax } 195181698Semax return (0); 196181698Semax} 197181698Semax 198181698Semaxstatic void 199181698Semaxpartition_cred_init_label(struct label *label) 200181698Semax{ 201181698Semax 202181698Semax SLOT_SET(label, 0); 203181698Semax} 204181698Semax 205181698Semaxstatic int 206181698Semaxpartition_cred_internalize_label(struct label *label, char *element_name, 207181698Semax char *element_data, int *claimed) 208181698Semax{ 209181698Semax 210181698Semax if (strcmp(MAC_PARTITION_LABEL_NAME, element_name) != 0) 211181698Semax return (0); 212181698Semax 213121054Semax (*claimed)++; 214121054Semax SLOT_SET(label, strtol(element_data, NULL, 10)); 215121054Semax return (0); 216121054Semax} 217 218static void 219partition_cred_relabel(struct ucred *cred, struct label *newlabel) 220{ 221 222 if (newlabel != NULL && SLOT(newlabel) != 0) 223 SLOT_SET(cred->cr_label, SLOT(newlabel)); 224} 225 226static int 227partition_inpcb_check_visible(struct ucred *cred, struct inpcb *inp, 228 struct label *inplabel) 229{ 230 int error; 231 232 error = partition_check(cred->cr_label, inp->inp_cred->cr_label); 233 234 return (error ? ENOENT : 0); 235} 236 237static int 238partition_proc_check_debug(struct ucred *cred, struct proc *p) 239{ 240 int error; 241 242 error = partition_check(cred->cr_label, p->p_ucred->cr_label); 243 244 return (error ? ESRCH : 0); 245} 246 247static int 248partition_proc_check_sched(struct ucred *cred, struct proc *p) 249{ 250 int error; 251 252 error = partition_check(cred->cr_label, p->p_ucred->cr_label); 253 254 return (error ? ESRCH : 0); 255} 256 257static int 258partition_proc_check_signal(struct ucred *cred, struct proc *p, 259 int signum) 260{ 261 int error; 262 263 error = partition_check(cred->cr_label, p->p_ucred->cr_label); 264 265 return (error ? ESRCH : 0); 266} 267 268static int 269partition_socket_check_visible(struct ucred *cred, struct socket *so, 270 struct label *solabel) 271{ 272 int error; 273 274 error = partition_check(cred->cr_label, so->so_cred->cr_label); 275 276 return (error ? ENOENT : 0); 277} 278 279static int 280partition_vnode_check_exec(struct ucred *cred, struct vnode *vp, 281 struct label *vplabel, struct image_params *imgp, 282 struct label *execlabel) 283{ 284 285 if (execlabel != NULL) { 286 /* 287 * We currently don't permit labels to be changed at 288 * exec-time as part of the partition model, so disallow 289 * non-NULL partition label changes in execlabel. 290 */ 291 if (SLOT(execlabel) != 0) 292 return (EINVAL); 293 } 294 295 return (0); 296} 297 298static struct mac_policy_ops partition_ops = 299{ 300 .mpo_cred_check_relabel = partition_cred_check_relabel, 301 .mpo_cred_check_visible = partition_cred_check_visible, 302 .mpo_cred_copy_label = partition_cred_copy_label, 303 .mpo_cred_create_init = partition_cred_create_init, 304 .mpo_cred_create_swapper = partition_cred_create_swapper, 305 .mpo_cred_destroy_label = partition_cred_destroy_label, 306 .mpo_cred_externalize_label = partition_cred_externalize_label, 307 .mpo_cred_init_label = partition_cred_init_label, 308 .mpo_cred_internalize_label = partition_cred_internalize_label, 309 .mpo_cred_relabel = partition_cred_relabel, 310 .mpo_inpcb_check_visible = partition_inpcb_check_visible, 311 .mpo_proc_check_debug = partition_proc_check_debug, 312 .mpo_proc_check_sched = partition_proc_check_sched, 313 .mpo_proc_check_signal = partition_proc_check_signal, 314 .mpo_socket_check_visible = partition_socket_check_visible, 315 .mpo_vnode_check_exec = partition_vnode_check_exec, 316}; 317 318MAC_POLICY_SET(&partition_ops, mac_partition, "TrustedBSD MAC/Partition", 319 MPC_LOADTIME_FLAG_UNLOADOK, &partition_slot); 320