xref: /freebsd/sys/security/mac/mac_net.c (revision 30af2c131bb05528f9b14518a7ed3e98c590b55e)
17bc82500SRobert Watson /*-
25c95417dSRobert Watson  * Copyright (c) 1999-2002, 2009, 2019 Robert N. M. Watson
37bc82500SRobert Watson  * Copyright (c) 2001 Ilmar S. Habibulin
4c66b4d8dSRobert Watson  * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
530d239bcSRobert Watson  * Copyright (c) 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  *
1230d239bcSRobert Watson  * This software was enhanced by SPARTA ISSO under SPAWAR contract
1330d239bcSRobert Watson  * N66001-04-C-6019 ("SEFOS").
1430d239bcSRobert Watson  *
156201265bSRobert Watson  * This software was developed for the FreeBSD Project in part by Network
166201265bSRobert Watson  * Associates Laboratories, the Security Research Division of Network
176201265bSRobert Watson  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
186201265bSRobert Watson  * as part of the DARPA CHATS research program.
197bc82500SRobert Watson  *
202087a58cSRobert Watson  * This software was developed at the University of Cambridge Computer
212087a58cSRobert Watson  * Laboratory with support from a grant from Google, Inc.
222087a58cSRobert 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>
46677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
47677b542eSDavid E. O'Brien 
487bc82500SRobert Watson #include "opt_mac.h"
49f9d0d524SRobert Watson 
507bc82500SRobert Watson #include <sys/param.h>
5195fab37eSRobert Watson #include <sys/kernel.h>
5295fab37eSRobert Watson #include <sys/lock.h>
53b656366bSBruce Evans #include <sys/malloc.h>
5495fab37eSRobert Watson #include <sys/mutex.h>
5595fab37eSRobert Watson #include <sys/mac.h>
56acd3428bSRobert Watson #include <sys/priv.h>
57f51e5803SRobert Watson #include <sys/sbuf.h>
582087a58cSRobert Watson #include <sys/sdt.h>
5995fab37eSRobert Watson #include <sys/systm.h>
6095fab37eSRobert Watson #include <sys/mount.h>
6195fab37eSRobert Watson #include <sys/file.h>
6295fab37eSRobert Watson #include <sys/namei.h>
63a557af22SRobert Watson #include <sys/protosw.h>
6495fab37eSRobert Watson #include <sys/socket.h>
6595fab37eSRobert Watson #include <sys/socketvar.h>
6695fab37eSRobert Watson #include <sys/sysctl.h>
6795fab37eSRobert Watson 
6895fab37eSRobert Watson #include <net/bpfdesc.h>
6995fab37eSRobert Watson #include <net/if.h>
7095fab37eSRobert Watson #include <net/if_var.h>
7195fab37eSRobert Watson 
72aed55708SRobert Watson #include <security/mac/mac_framework.h>
7328e65e3dSRobert Watson #include <security/mac/mac_internal.h>
740efd6615SRobert Watson #include <security/mac/mac_policy.h>
75a3df768bSRobert Watson 
76c66b4d8dSRobert Watson /*
77e678cce9SRobert Watson  * XXXRW: struct ifnet locking is incomplete in the network code, so we use
78e678cce9SRobert Watson  * our own global mutex for struct ifnet.  Non-ideal, but should help in the
79e678cce9SRobert Watson  * SMP environment.
805c95417dSRobert Watson  *
815c95417dSRobert Watson  * This lock is acquired only if a loaded policy is using ifnet labeling.
825c95417dSRobert Watson  * This should not ever change during a MAC policy check, itself, but could
835c95417dSRobert Watson  * change during setup/return from a check, so we have to condition unlock on
845c95417dSRobert Watson  * previous lock.
852220907bSRobert Watson  */
86b9b0dac3SRobert Watson struct mtx mac_ifnet_mtx;
872220907bSRobert Watson MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF);
882220907bSRobert Watson 
89e678cce9SRobert Watson /*
90e678cce9SRobert Watson  * Retrieve the label associated with an mbuf by searching for the tag.
91e678cce9SRobert Watson  * Depending on the value of mac_labelmbufs, it's possible that a label will
92e678cce9SRobert Watson  * not be present, in which case NULL is returned.  Policies must handle the
93e678cce9SRobert Watson  * possibility of an mbuf not having label storage if they do not enforce
94e678cce9SRobert Watson  * early loading.
95e678cce9SRobert Watson  */
96c66b4d8dSRobert Watson struct label *
9726ae2b86SRobert Watson mac_mbuf_to_label(struct mbuf *m)
9810eeb10cSRobert Watson {
99225bff6fSRobert Watson 	struct m_tag *tag;
10010eeb10cSRobert Watson 	struct label *label;
10110eeb10cSRobert Watson 
10226ae2b86SRobert Watson 	if (m == NULL)
103583284e1SRobert Watson 		return (NULL);
10426ae2b86SRobert Watson 	tag = m_tag_find(m, PACKET_TAG_MACLABEL, NULL);
105583284e1SRobert Watson 	if (tag == NULL)
106583284e1SRobert Watson 		return (NULL);
107225bff6fSRobert Watson 	label = (struct label *)(tag+1);
10810eeb10cSRobert Watson 	return (label);
10910eeb10cSRobert Watson }
11010eeb10cSRobert Watson 
111eca8a663SRobert Watson static struct label *
112eca8a663SRobert Watson mac_bpfdesc_label_alloc(void)
113eca8a663SRobert Watson {
114eca8a663SRobert Watson 	struct label *label;
115eca8a663SRobert Watson 
116eca8a663SRobert Watson 	label = mac_labelzone_alloc(M_WAITOK);
117fa765671SRobert Watson 	MAC_POLICY_PERFORM(bpfdesc_init_label, label);
118eca8a663SRobert Watson 	return (label);
119eca8a663SRobert Watson }
120eca8a663SRobert Watson 
12108bcdc58SRobert Watson void
12230d239bcSRobert Watson mac_bpfdesc_init(struct bpf_d *d)
12308bcdc58SRobert Watson {
12408bcdc58SRobert Watson 
1256356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_BPFDESC)
12626ae2b86SRobert Watson 		d->bd_label = mac_bpfdesc_label_alloc();
1276356dba0SRobert Watson 	else
1286356dba0SRobert Watson 		d->bd_label = NULL;
12908bcdc58SRobert Watson }
13008bcdc58SRobert Watson 
131eca8a663SRobert Watson static struct label *
132eca8a663SRobert Watson mac_ifnet_label_alloc(void)
133f7b951a8SRobert Watson {
134eca8a663SRobert Watson 	struct label *label;
135f7b951a8SRobert Watson 
136eca8a663SRobert Watson 	label = mac_labelzone_alloc(M_WAITOK);
137fa765671SRobert Watson 	MAC_POLICY_PERFORM(ifnet_init_label, label);
138eca8a663SRobert Watson 	return (label);
139f7b951a8SRobert Watson }
140f7b951a8SRobert Watson 
14108bcdc58SRobert Watson void
14230d239bcSRobert Watson mac_ifnet_init(struct ifnet *ifp)
14308bcdc58SRobert Watson {
14408bcdc58SRobert Watson 
1456356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_IFNET)
146*30af2c13SJustin Hibbits 		if_setmaclabel(ifp, mac_ifnet_label_alloc());
1476356dba0SRobert Watson 	else
148*30af2c13SJustin Hibbits 		if_setmaclabel(ifp, NULL);
149eca8a663SRobert Watson }
150eca8a663SRobert Watson 
15187807196SRobert Watson int
15230d239bcSRobert Watson mac_mbuf_tag_init(struct m_tag *tag, int flag)
15308bcdc58SRobert Watson {
154225bff6fSRobert Watson 	struct label *label;
1556d1a6a9aSRobert Watson 	int error;
15656c15412SRobert Watson 
157225bff6fSRobert Watson 	label = (struct label *) (tag + 1);
158225bff6fSRobert Watson 	mac_init_label(label);
15908bcdc58SRobert Watson 
16040202729SRobert Watson 	if (flag & M_WAITOK)
161fa765671SRobert Watson 		MAC_POLICY_CHECK(mbuf_init_label, label, flag);
16240202729SRobert Watson 	else
163fa765671SRobert Watson 		MAC_POLICY_CHECK_NOSLEEP(mbuf_init_label, label, flag);
16456c15412SRobert Watson 	if (error) {
165fa765671SRobert Watson 		MAC_POLICY_PERFORM_NOSLEEP(mbuf_destroy_label, label);
166225bff6fSRobert Watson 		mac_destroy_label(label);
16756c15412SRobert Watson 	}
16856c15412SRobert Watson 	return (error);
16908bcdc58SRobert Watson }
17008bcdc58SRobert Watson 
171225bff6fSRobert Watson int
17230d239bcSRobert Watson mac_mbuf_init(struct mbuf *m, int flag)
173225bff6fSRobert Watson {
174225bff6fSRobert Watson 	struct m_tag *tag;
175225bff6fSRobert Watson 	int error;
176225bff6fSRobert Watson 
177225bff6fSRobert Watson 	M_ASSERTPKTHDR(m);
178225bff6fSRobert Watson 
1796356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_MBUF) {
180225bff6fSRobert Watson 		tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label),
181225bff6fSRobert Watson 		    flag);
182225bff6fSRobert Watson 		if (tag == NULL)
183225bff6fSRobert Watson 			return (ENOMEM);
18430d239bcSRobert Watson 		error = mac_mbuf_tag_init(tag, flag);
185225bff6fSRobert Watson 		if (error) {
186225bff6fSRobert Watson 			m_tag_free(tag);
187225bff6fSRobert Watson 			return (error);
188225bff6fSRobert Watson 		}
189225bff6fSRobert Watson 		m_tag_prepend(m, tag);
1906356dba0SRobert Watson 	}
191225bff6fSRobert Watson 	return (0);
192225bff6fSRobert Watson }
193225bff6fSRobert Watson 
194eca8a663SRobert Watson static void
195eca8a663SRobert Watson mac_bpfdesc_label_free(struct label *label)
196eca8a663SRobert Watson {
19783985c26SRobert Watson 
198fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_destroy_label, label);
199eca8a663SRobert Watson 	mac_labelzone_free(label);
20087807196SRobert Watson }
20187807196SRobert Watson 
202763bbd2fSRobert Watson void
20330d239bcSRobert Watson mac_bpfdesc_destroy(struct bpf_d *d)
20408bcdc58SRobert Watson {
20508bcdc58SRobert Watson 
2066356dba0SRobert Watson 	if (d->bd_label != NULL) {
20726ae2b86SRobert Watson 		mac_bpfdesc_label_free(d->bd_label);
20826ae2b86SRobert Watson 		d->bd_label = NULL;
20908bcdc58SRobert Watson 	}
2106356dba0SRobert Watson }
21108bcdc58SRobert Watson 
212f7b951a8SRobert Watson static void
213eca8a663SRobert Watson mac_ifnet_label_free(struct label *label)
214f7b951a8SRobert Watson {
215f7b951a8SRobert Watson 
216fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_destroy_label, label);
217eca8a663SRobert Watson 	mac_labelzone_free(label);
218f7b951a8SRobert Watson }
219f7b951a8SRobert Watson 
22087807196SRobert Watson void
22130d239bcSRobert Watson mac_ifnet_destroy(struct ifnet *ifp)
22287807196SRobert Watson {
223*30af2c13SJustin Hibbits 	struct label *label = if_getmaclabel(ifp);
224*30af2c13SJustin Hibbits 	if (label != NULL) {
225*30af2c13SJustin Hibbits 		mac_ifnet_label_free(label);
226*30af2c13SJustin Hibbits 		if_setmaclabel(ifp, NULL);
227eca8a663SRobert Watson 	}
2286356dba0SRobert Watson }
229eca8a663SRobert Watson 
23087807196SRobert Watson void
23130d239bcSRobert Watson mac_mbuf_tag_destroy(struct m_tag *tag)
23287807196SRobert Watson {
233225bff6fSRobert Watson 	struct label *label;
23487807196SRobert Watson 
235225bff6fSRobert Watson 	label = (struct label *)(tag+1);
236225bff6fSRobert Watson 
237fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(mbuf_destroy_label, label);
238225bff6fSRobert Watson 	mac_destroy_label(label);
23908bcdc58SRobert Watson }
24008bcdc58SRobert Watson 
241e678cce9SRobert Watson /*
24230d239bcSRobert Watson  * mac_mbuf_tag_copy is called when an mbuf header is duplicated, in which
243e678cce9SRobert Watson  * case the labels must also be duplicated.
244e678cce9SRobert Watson  */
245b0323ea3SRobert Watson void
24630d239bcSRobert Watson mac_mbuf_tag_copy(struct m_tag *src, struct m_tag *dest)
247225bff6fSRobert Watson {
248225bff6fSRobert Watson 	struct label *src_label, *dest_label;
249225bff6fSRobert Watson 
250225bff6fSRobert Watson 	src_label = (struct label *)(src+1);
251225bff6fSRobert Watson 	dest_label = (struct label *)(dest+1);
252225bff6fSRobert Watson 
253225bff6fSRobert Watson 	/*
25430d239bcSRobert Watson 	 * mac_mbuf_tag_init() is called on the target tag in m_tag_copy(),
255e678cce9SRobert Watson 	 * so we don't need to call it here.
256225bff6fSRobert Watson 	 */
257fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(mbuf_copy_label, src_label, dest_label);
258225bff6fSRobert Watson }
259225bff6fSRobert Watson 
2603c308b09SRobert Watson void
26130d239bcSRobert Watson mac_mbuf_copy(struct mbuf *m_from, struct mbuf *m_to)
2623c308b09SRobert Watson {
2633c308b09SRobert Watson 	struct label *src_label, *dest_label;
2643c308b09SRobert Watson 
2653ad3d9c5SRobert Watson 	if (mac_policy_count == 0)
2663ad3d9c5SRobert Watson 		return;
2673ad3d9c5SRobert Watson 
2683c308b09SRobert Watson 	src_label = mac_mbuf_to_label(m_from);
2693c308b09SRobert Watson 	dest_label = mac_mbuf_to_label(m_to);
2703c308b09SRobert Watson 
271fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(mbuf_copy_label, src_label, dest_label);
2723c308b09SRobert Watson }
2733c308b09SRobert Watson 
2742220907bSRobert Watson static void
27530d239bcSRobert Watson mac_ifnet_copy_label(struct label *src, struct label *dest)
2762220907bSRobert Watson {
2772220907bSRobert Watson 
278fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_copy_label, src, dest);
2792220907bSRobert Watson }
2802220907bSRobert Watson 
28169bbb5b1SRobert Watson static int
28230d239bcSRobert Watson mac_ifnet_externalize_label(struct label *label, char *elements,
28383b7b0edSRobert Watson     char *outbuf, size_t outbuflen)
28469bbb5b1SRobert Watson {
28569bbb5b1SRobert Watson 	int error;
28669bbb5b1SRobert Watson 
287fa765671SRobert Watson 	MAC_POLICY_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen);
288f7b951a8SRobert Watson 
289f7b951a8SRobert Watson 	return (error);
290f7b951a8SRobert Watson }
291f7b951a8SRobert Watson 
292f7b951a8SRobert Watson static int
29330d239bcSRobert Watson mac_ifnet_internalize_label(struct label *label, char *string)
294f7b951a8SRobert Watson {
295f7b951a8SRobert Watson 	int error;
296f7b951a8SRobert Watson 
297fa765671SRobert Watson 	MAC_POLICY_INTERNALIZE(ifnet, label, string);
298f7b951a8SRobert Watson 
299f7b951a8SRobert Watson 	return (error);
300f7b951a8SRobert Watson }
301f7b951a8SRobert Watson 
30295fab37eSRobert Watson void
30330d239bcSRobert Watson mac_ifnet_create(struct ifnet *ifp)
30495fab37eSRobert Watson {
3055c95417dSRobert Watson 	int locked;
30695fab37eSRobert Watson 
3073de40469SRobert Watson 	if (mac_policy_count == 0)
3083de40469SRobert Watson 		return;
3093de40469SRobert Watson 
3105c95417dSRobert Watson 	MAC_IFNET_LOCK(ifp, locked);
311*30af2c13SJustin Hibbits 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_create, ifp, if_getmaclabel(ifp));
3125c95417dSRobert Watson 	MAC_IFNET_UNLOCK(ifp, locked);
31395fab37eSRobert Watson }
31495fab37eSRobert Watson 
31595fab37eSRobert Watson void
31630d239bcSRobert Watson mac_bpfdesc_create(struct ucred *cred, struct bpf_d *d)
31795fab37eSRobert Watson {
31895fab37eSRobert Watson 
319fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_create, cred, d, d->bd_label);
32095fab37eSRobert Watson }
32195fab37eSRobert Watson 
32295fab37eSRobert Watson void
32330d239bcSRobert Watson mac_bpfdesc_create_mbuf(struct bpf_d *d, struct mbuf *m)
32495fab37eSRobert Watson {
32510eeb10cSRobert Watson 	struct label *label;
32610eeb10cSRobert Watson 
327e4b3229aSAlexander V. Chernikov 	/* Assume reader lock is enough. */
32826ae2b86SRobert Watson 	BPFD_LOCK_ASSERT(d);
329e33d9f29SRobert Watson 
3303de40469SRobert Watson 	if (mac_policy_count == 0)
3313de40469SRobert Watson 		return;
3323de40469SRobert Watson 
33326ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
33495fab37eSRobert Watson 
335fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_create_mbuf, d, d->bd_label, m,
336fa765671SRobert Watson 	    label);
33795fab37eSRobert Watson }
33895fab37eSRobert Watson 
33995fab37eSRobert Watson void
340f77697ddSMateusz Guzik mac_ifnet_create_mbuf_impl(struct ifnet *ifp, struct mbuf *m)
34195fab37eSRobert Watson {
34210eeb10cSRobert Watson 	struct label *label;
3435c95417dSRobert Watson 	int locked;
34410eeb10cSRobert Watson 
34526ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
34695fab37eSRobert Watson 
3475c95417dSRobert Watson 	MAC_IFNET_LOCK(ifp, locked);
348*30af2c13SJustin Hibbits 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_create_mbuf, ifp, if_getmaclabel(ifp), m,
349fa765671SRobert Watson 	    label);
3505c95417dSRobert Watson 	MAC_IFNET_UNLOCK(ifp, locked);
35195fab37eSRobert Watson }
35295fab37eSRobert Watson 
3532087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(bpfdesc_check_receive, "struct bpf_d *",
3542087a58cSRobert Watson     "struct ifnet *");
3552087a58cSRobert Watson 
35695fab37eSRobert Watson int
35730d239bcSRobert Watson mac_bpfdesc_check_receive(struct bpf_d *d, struct ifnet *ifp)
35895fab37eSRobert Watson {
3595c95417dSRobert Watson 	int error, locked;
36095fab37eSRobert Watson 
361e4b3229aSAlexander V. Chernikov 	/* Assume reader lock is enough. */
36226ae2b86SRobert Watson 	BPFD_LOCK_ASSERT(d);
363e33d9f29SRobert Watson 
3643de40469SRobert Watson 	if (mac_policy_count == 0)
3653de40469SRobert Watson 		return (0);
3663de40469SRobert Watson 
3675c95417dSRobert Watson 	MAC_IFNET_LOCK(ifp, locked);
368fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(bpfdesc_check_receive, d, d->bd_label, ifp,
369*30af2c13SJustin Hibbits 	    if_getmaclabel(ifp));
3702087a58cSRobert Watson 	MAC_CHECK_PROBE2(bpfdesc_check_receive, error, d, ifp);
3715c95417dSRobert Watson 	MAC_IFNET_UNLOCK(ifp, locked);
37295fab37eSRobert Watson 
37395fab37eSRobert Watson 	return (error);
37495fab37eSRobert Watson }
37595fab37eSRobert Watson 
3762087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(ifnet_check_transmit, "struct ifnet *",
3772087a58cSRobert Watson     "struct mbuf *");
3782087a58cSRobert Watson 
37995fab37eSRobert Watson int
380f77697ddSMateusz Guzik mac_ifnet_check_transmit_impl(struct ifnet *ifp, struct mbuf *m)
38195fab37eSRobert Watson {
38210eeb10cSRobert Watson 	struct label *label;
3835c95417dSRobert Watson 	int error, locked;
38495fab37eSRobert Watson 
38526ae2b86SRobert Watson 	M_ASSERTPKTHDR(m);
386225bff6fSRobert Watson 
38726ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
38895fab37eSRobert Watson 
3895c95417dSRobert Watson 	MAC_IFNET_LOCK(ifp, locked);
390*30af2c13SJustin Hibbits 	MAC_POLICY_CHECK_NOSLEEP(ifnet_check_transmit, ifp, if_getmaclabel(ifp), m,
39140202729SRobert Watson 	    label);
3922087a58cSRobert Watson 	MAC_CHECK_PROBE2(ifnet_check_transmit, error, ifp, m);
3935c95417dSRobert Watson 	MAC_IFNET_UNLOCK(ifp, locked);
39495fab37eSRobert Watson 
39595fab37eSRobert Watson 	return (error);
39695fab37eSRobert Watson }
39795fab37eSRobert Watson 
39895fab37eSRobert Watson int
39930d239bcSRobert Watson mac_ifnet_ioctl_get(struct ucred *cred, struct ifreq *ifr,
40026ae2b86SRobert Watson     struct ifnet *ifp)
40195fab37eSRobert Watson {
402f7b951a8SRobert Watson 	char *elements, *buffer;
4032220907bSRobert Watson 	struct label *intlabel;
404f7b951a8SRobert Watson 	struct mac mac;
4055c95417dSRobert Watson 	int error, locked;
40695fab37eSRobert Watson 
4076356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_IFNET))
4086356dba0SRobert Watson 		return (EINVAL);
4096356dba0SRobert Watson 
410541d96aaSBrooks Davis 	error = copyin(ifr_data_get_ptr(ifr), &mac, sizeof(mac));
41195fab37eSRobert Watson 	if (error)
41295fab37eSRobert Watson 		return (error);
41395fab37eSRobert Watson 
414f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
415f7b951a8SRobert Watson 	if (error)
416f7b951a8SRobert Watson 		return (error);
417f7b951a8SRobert Watson 
418a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
419f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
420f7b951a8SRobert Watson 	if (error) {
421f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
422f7b951a8SRobert Watson 		return (error);
423f7b951a8SRobert Watson 	}
424f7b951a8SRobert Watson 
425a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
4262220907bSRobert Watson 	intlabel = mac_ifnet_label_alloc();
4275c95417dSRobert Watson 	MAC_IFNET_LOCK(ifp, locked);
428*30af2c13SJustin Hibbits 	mac_ifnet_copy_label(if_getmaclabel(ifp), intlabel);
4295c95417dSRobert Watson 	MAC_IFNET_UNLOCK(ifp, locked);
43030d239bcSRobert Watson 	error = mac_ifnet_externalize_label(intlabel, elements, buffer,
4318f3476b3SRobert Watson 	    mac.m_buflen);
4322220907bSRobert Watson 	mac_ifnet_label_free(intlabel);
433f7b951a8SRobert Watson 	if (error == 0)
434f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
435f7b951a8SRobert Watson 
436f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
437f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
438f7b951a8SRobert Watson 
439f7b951a8SRobert Watson 	return (error);
44095fab37eSRobert Watson }
44195fab37eSRobert Watson 
44295fab37eSRobert Watson int
44330d239bcSRobert Watson mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp)
44495fab37eSRobert Watson {
445eca8a663SRobert Watson 	struct label *intlabel;
446f7b951a8SRobert Watson 	struct mac mac;
447f7b951a8SRobert Watson 	char *buffer;
4485c95417dSRobert Watson 	int error, locked;
44995fab37eSRobert Watson 
4506356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_IFNET))
4516356dba0SRobert Watson 		return (EINVAL);
4526356dba0SRobert Watson 
453541d96aaSBrooks Davis 	error = copyin(ifr_data_get_ptr(ifr), &mac, sizeof(mac));
45495fab37eSRobert Watson 	if (error)
45595fab37eSRobert Watson 		return (error);
45695fab37eSRobert Watson 
457f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
45895fab37eSRobert Watson 	if (error)
45995fab37eSRobert Watson 		return (error);
46095fab37eSRobert Watson 
461a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
462f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
463f7b951a8SRobert Watson 	if (error) {
464f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
465f7b951a8SRobert Watson 		return (error);
466f7b951a8SRobert Watson 	}
467f7b951a8SRobert Watson 
468eca8a663SRobert Watson 	intlabel = mac_ifnet_label_alloc();
46930d239bcSRobert Watson 	error = mac_ifnet_internalize_label(intlabel, buffer);
470f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
471f7b951a8SRobert Watson 	if (error) {
472eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
473f7b951a8SRobert Watson 		return (error);
474f7b951a8SRobert Watson 	}
475f7b951a8SRobert Watson 
47695fab37eSRobert Watson 	/*
477acd3428bSRobert Watson 	 * XXX: Note that this is a redundant privilege check, since policies
478e678cce9SRobert Watson 	 * impose this check themselves if required by the policy
479acd3428bSRobert Watson 	 * Eventually, this should go away.
48095fab37eSRobert Watson 	 */
481cc426dd3SMateusz Guzik 	error = priv_check_cred(cred, PRIV_NET_SETIFMAC);
482f7b951a8SRobert Watson 	if (error) {
483eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
484f7b951a8SRobert Watson 		return (error);
485f7b951a8SRobert Watson 	}
48695fab37eSRobert Watson 
4875c95417dSRobert Watson 	MAC_IFNET_LOCK(ifp, locked);
488fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(ifnet_check_relabel, cred, ifp,
489*30af2c13SJustin Hibbits 	    if_getmaclabel(ifp), intlabel);
490f7b951a8SRobert Watson 	if (error) {
4915c95417dSRobert Watson 		MAC_IFNET_UNLOCK(ifp, locked);
492eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
493f7b951a8SRobert Watson 		return (error);
494f7b951a8SRobert Watson 	}
49595fab37eSRobert Watson 
496*30af2c13SJustin Hibbits 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_relabel, cred, ifp, if_getmaclabel(ifp),
49740202729SRobert Watson 	    intlabel);
4985c95417dSRobert Watson 	MAC_IFNET_UNLOCK(ifp, locked);
49995fab37eSRobert Watson 
500eca8a663SRobert Watson 	mac_ifnet_label_free(intlabel);
501f7b951a8SRobert Watson 	return (0);
50295fab37eSRobert Watson }
503