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
partition_check(struct label * subject,struct label * object)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
partition_cred_check_relabel(struct ucred * cred,struct label * newlabel)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
partition_cred_check_visible(struct ucred * cr1,struct ucred * cr2)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
partition_cred_copy_label(struct label * src,struct label * dest)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
partition_cred_create_init(struct ucred * cred)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
partition_cred_create_swapper(struct ucred * cred)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
partition_cred_destroy_label(struct label * label)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
partition_cred_externalize_label(struct label * label,char * element_name,struct sbuf * sb,int * claimed)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
partition_cred_init_label(struct label * label)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
partition_cred_internalize_label(struct label * label,char * element_name,char * element_data,int * claimed)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
partition_cred_relabel(struct ucred * cred,struct label * newlabel)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
partition_inpcb_check_visible(struct ucred * cred,struct inpcb * inp,struct label * inplabel)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
partition_proc_check_debug(struct ucred * cred,struct proc * p)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
partition_proc_check_sched(struct ucred * cred,struct proc * p)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
partition_proc_check_signal(struct ucred * cred,struct proc * p,int signum)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
partition_socket_check_visible(struct ucred * cred,struct socket * so,struct label * solabel)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
partition_vnode_check_exec(struct ucred * cred,struct vnode * vp,struct label * vplabel,struct image_params * imgp,struct label * execlabel)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