xref: /freebsd/sys/security/mac_partition/mac_partition.c (revision db33c6f3ae9d1231087710068ee4ea5398aacca7)
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