xref: /freebsd/sys/security/mac/mac_net.c (revision fa76567150773e0aab5fdd883cf7652a27c7c25e)
17bc82500SRobert Watson /*-
22087a58cSRobert Watson  * Copyright (c) 1999-2002, 2009 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 
482087a58cSRobert Watson #include "opt_kdtrace.h"
497bc82500SRobert Watson #include "opt_mac.h"
50f9d0d524SRobert Watson 
517bc82500SRobert Watson #include <sys/param.h>
5295fab37eSRobert Watson #include <sys/kernel.h>
5395fab37eSRobert Watson #include <sys/lock.h>
54b656366bSBruce Evans #include <sys/malloc.h>
5595fab37eSRobert Watson #include <sys/mutex.h>
5695fab37eSRobert Watson #include <sys/mac.h>
57acd3428bSRobert Watson #include <sys/priv.h>
58f51e5803SRobert Watson #include <sys/sbuf.h>
592087a58cSRobert Watson #include <sys/sdt.h>
6095fab37eSRobert Watson #include <sys/systm.h>
6195fab37eSRobert Watson #include <sys/mount.h>
6295fab37eSRobert Watson #include <sys/file.h>
6395fab37eSRobert Watson #include <sys/namei.h>
64a557af22SRobert Watson #include <sys/protosw.h>
6595fab37eSRobert Watson #include <sys/socket.h>
6695fab37eSRobert Watson #include <sys/socketvar.h>
6795fab37eSRobert Watson #include <sys/sysctl.h>
6895fab37eSRobert Watson 
6995fab37eSRobert Watson #include <net/bpfdesc.h>
7095fab37eSRobert Watson #include <net/if.h>
7195fab37eSRobert Watson #include <net/if_var.h>
7295fab37eSRobert Watson 
73aed55708SRobert Watson #include <security/mac/mac_framework.h>
7428e65e3dSRobert Watson #include <security/mac/mac_internal.h>
750efd6615SRobert Watson #include <security/mac/mac_policy.h>
76a3df768bSRobert Watson 
77c66b4d8dSRobert Watson /*
78e678cce9SRobert Watson  * XXXRW: struct ifnet locking is incomplete in the network code, so we use
79e678cce9SRobert Watson  * our own global mutex for struct ifnet.  Non-ideal, but should help in the
80e678cce9SRobert Watson  * SMP environment.
812220907bSRobert Watson  */
82b9b0dac3SRobert Watson struct mtx mac_ifnet_mtx;
832220907bSRobert Watson MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF);
842220907bSRobert Watson 
85e678cce9SRobert Watson /*
86e678cce9SRobert Watson  * Retrieve the label associated with an mbuf by searching for the tag.
87e678cce9SRobert Watson  * Depending on the value of mac_labelmbufs, it's possible that a label will
88e678cce9SRobert Watson  * not be present, in which case NULL is returned.  Policies must handle the
89e678cce9SRobert Watson  * possibility of an mbuf not having label storage if they do not enforce
90e678cce9SRobert Watson  * early loading.
91e678cce9SRobert Watson  */
92c66b4d8dSRobert Watson struct label *
9326ae2b86SRobert Watson mac_mbuf_to_label(struct mbuf *m)
9410eeb10cSRobert Watson {
95225bff6fSRobert Watson 	struct m_tag *tag;
9610eeb10cSRobert Watson 	struct label *label;
9710eeb10cSRobert Watson 
9826ae2b86SRobert Watson 	if (m == NULL)
99583284e1SRobert Watson 		return (NULL);
10026ae2b86SRobert Watson 	tag = m_tag_find(m, PACKET_TAG_MACLABEL, NULL);
101583284e1SRobert Watson 	if (tag == NULL)
102583284e1SRobert Watson 		return (NULL);
103225bff6fSRobert Watson 	label = (struct label *)(tag+1);
10410eeb10cSRobert Watson 	return (label);
10510eeb10cSRobert Watson }
10610eeb10cSRobert Watson 
107eca8a663SRobert Watson static struct label *
108eca8a663SRobert Watson mac_bpfdesc_label_alloc(void)
109eca8a663SRobert Watson {
110eca8a663SRobert Watson 	struct label *label;
111eca8a663SRobert Watson 
112eca8a663SRobert Watson 	label = mac_labelzone_alloc(M_WAITOK);
113fa765671SRobert Watson 	MAC_POLICY_PERFORM(bpfdesc_init_label, label);
114eca8a663SRobert Watson 	return (label);
115eca8a663SRobert Watson }
116eca8a663SRobert Watson 
11708bcdc58SRobert Watson void
11830d239bcSRobert Watson mac_bpfdesc_init(struct bpf_d *d)
11908bcdc58SRobert Watson {
12008bcdc58SRobert Watson 
1216356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_BPFDESC)
12226ae2b86SRobert Watson 		d->bd_label = mac_bpfdesc_label_alloc();
1236356dba0SRobert Watson 	else
1246356dba0SRobert Watson 		d->bd_label = NULL;
12508bcdc58SRobert Watson }
12608bcdc58SRobert Watson 
127eca8a663SRobert Watson static struct label *
128eca8a663SRobert Watson mac_ifnet_label_alloc(void)
129f7b951a8SRobert Watson {
130eca8a663SRobert Watson 	struct label *label;
131f7b951a8SRobert Watson 
132eca8a663SRobert Watson 	label = mac_labelzone_alloc(M_WAITOK);
133fa765671SRobert Watson 	MAC_POLICY_PERFORM(ifnet_init_label, label);
134eca8a663SRobert Watson 	return (label);
135f7b951a8SRobert Watson }
136f7b951a8SRobert Watson 
13708bcdc58SRobert Watson void
13830d239bcSRobert Watson mac_ifnet_init(struct ifnet *ifp)
13908bcdc58SRobert Watson {
14008bcdc58SRobert Watson 
1416356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_IFNET)
142eca8a663SRobert Watson 		ifp->if_label = mac_ifnet_label_alloc();
1436356dba0SRobert Watson 	else
1446356dba0SRobert Watson 		ifp->if_label = NULL;
145eca8a663SRobert Watson }
146eca8a663SRobert Watson 
14787807196SRobert Watson int
14830d239bcSRobert Watson mac_mbuf_tag_init(struct m_tag *tag, int flag)
14908bcdc58SRobert Watson {
150225bff6fSRobert Watson 	struct label *label;
1516d1a6a9aSRobert Watson 	int error;
15256c15412SRobert Watson 
153225bff6fSRobert Watson 	label = (struct label *) (tag + 1);
154225bff6fSRobert Watson 	mac_init_label(label);
15508bcdc58SRobert Watson 
15640202729SRobert Watson 	if (flag & M_WAITOK)
157fa765671SRobert Watson 		MAC_POLICY_CHECK(mbuf_init_label, label, flag);
15840202729SRobert Watson 	else
159fa765671SRobert Watson 		MAC_POLICY_CHECK_NOSLEEP(mbuf_init_label, label, flag);
16056c15412SRobert Watson 	if (error) {
161fa765671SRobert Watson 		MAC_POLICY_PERFORM_NOSLEEP(mbuf_destroy_label, label);
162225bff6fSRobert Watson 		mac_destroy_label(label);
16356c15412SRobert Watson 	}
16456c15412SRobert Watson 	return (error);
16508bcdc58SRobert Watson }
16608bcdc58SRobert Watson 
167225bff6fSRobert Watson int
16830d239bcSRobert Watson mac_mbuf_init(struct mbuf *m, int flag)
169225bff6fSRobert Watson {
170225bff6fSRobert Watson 	struct m_tag *tag;
171225bff6fSRobert Watson 	int error;
172225bff6fSRobert Watson 
173225bff6fSRobert Watson 	M_ASSERTPKTHDR(m);
174225bff6fSRobert Watson 
1756356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_MBUF) {
176225bff6fSRobert Watson 		tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label),
177225bff6fSRobert Watson 		    flag);
178225bff6fSRobert Watson 		if (tag == NULL)
179225bff6fSRobert Watson 			return (ENOMEM);
18030d239bcSRobert Watson 		error = mac_mbuf_tag_init(tag, flag);
181225bff6fSRobert Watson 		if (error) {
182225bff6fSRobert Watson 			m_tag_free(tag);
183225bff6fSRobert Watson 			return (error);
184225bff6fSRobert Watson 		}
185225bff6fSRobert Watson 		m_tag_prepend(m, tag);
1866356dba0SRobert Watson 	}
187225bff6fSRobert Watson 	return (0);
188225bff6fSRobert Watson }
189225bff6fSRobert Watson 
190eca8a663SRobert Watson static void
191eca8a663SRobert Watson mac_bpfdesc_label_free(struct label *label)
192eca8a663SRobert Watson {
19383985c26SRobert Watson 
194fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_destroy_label, label);
195eca8a663SRobert Watson 	mac_labelzone_free(label);
19687807196SRobert Watson }
19787807196SRobert Watson 
198763bbd2fSRobert Watson void
19930d239bcSRobert Watson mac_bpfdesc_destroy(struct bpf_d *d)
20008bcdc58SRobert Watson {
20108bcdc58SRobert Watson 
2026356dba0SRobert Watson 	if (d->bd_label != NULL) {
20326ae2b86SRobert Watson 		mac_bpfdesc_label_free(d->bd_label);
20426ae2b86SRobert Watson 		d->bd_label = NULL;
20508bcdc58SRobert Watson 	}
2066356dba0SRobert Watson }
20708bcdc58SRobert Watson 
208f7b951a8SRobert Watson static void
209eca8a663SRobert Watson mac_ifnet_label_free(struct label *label)
210f7b951a8SRobert Watson {
211f7b951a8SRobert Watson 
212fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_destroy_label, label);
213eca8a663SRobert Watson 	mac_labelzone_free(label);
214f7b951a8SRobert Watson }
215f7b951a8SRobert Watson 
21687807196SRobert Watson void
21730d239bcSRobert Watson mac_ifnet_destroy(struct ifnet *ifp)
21887807196SRobert Watson {
21987807196SRobert Watson 
2206356dba0SRobert Watson 	if (ifp->if_label != NULL) {
221eca8a663SRobert Watson 		mac_ifnet_label_free(ifp->if_label);
222eca8a663SRobert Watson 		ifp->if_label = NULL;
223eca8a663SRobert Watson 	}
2246356dba0SRobert Watson }
225eca8a663SRobert Watson 
22687807196SRobert Watson void
22730d239bcSRobert Watson mac_mbuf_tag_destroy(struct m_tag *tag)
22887807196SRobert Watson {
229225bff6fSRobert Watson 	struct label *label;
23087807196SRobert Watson 
231225bff6fSRobert Watson 	label = (struct label *)(tag+1);
232225bff6fSRobert Watson 
233fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(mbuf_destroy_label, label);
234225bff6fSRobert Watson 	mac_destroy_label(label);
23508bcdc58SRobert Watson }
23608bcdc58SRobert Watson 
237e678cce9SRobert Watson /*
23830d239bcSRobert Watson  * mac_mbuf_tag_copy is called when an mbuf header is duplicated, in which
239e678cce9SRobert Watson  * case the labels must also be duplicated.
240e678cce9SRobert Watson  */
241b0323ea3SRobert Watson void
24230d239bcSRobert Watson mac_mbuf_tag_copy(struct m_tag *src, struct m_tag *dest)
243225bff6fSRobert Watson {
244225bff6fSRobert Watson 	struct label *src_label, *dest_label;
245225bff6fSRobert Watson 
246225bff6fSRobert Watson 	src_label = (struct label *)(src+1);
247225bff6fSRobert Watson 	dest_label = (struct label *)(dest+1);
248225bff6fSRobert Watson 
249225bff6fSRobert Watson 	/*
25030d239bcSRobert Watson 	 * mac_mbuf_tag_init() is called on the target tag in m_tag_copy(),
251e678cce9SRobert Watson 	 * so we don't need to call it here.
252225bff6fSRobert Watson 	 */
253fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(mbuf_copy_label, src_label, dest_label);
254225bff6fSRobert Watson }
255225bff6fSRobert Watson 
2563c308b09SRobert Watson void
25730d239bcSRobert Watson mac_mbuf_copy(struct mbuf *m_from, struct mbuf *m_to)
2583c308b09SRobert Watson {
2593c308b09SRobert Watson 	struct label *src_label, *dest_label;
2603c308b09SRobert Watson 
2613c308b09SRobert Watson 	src_label = mac_mbuf_to_label(m_from);
2623c308b09SRobert Watson 	dest_label = mac_mbuf_to_label(m_to);
2633c308b09SRobert Watson 
264fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(mbuf_copy_label, src_label, dest_label);
2653c308b09SRobert Watson }
2663c308b09SRobert Watson 
2672220907bSRobert Watson static void
26830d239bcSRobert Watson mac_ifnet_copy_label(struct label *src, struct label *dest)
2692220907bSRobert Watson {
2702220907bSRobert Watson 
271fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_copy_label, src, dest);
2722220907bSRobert Watson }
2732220907bSRobert Watson 
27469bbb5b1SRobert Watson static int
27530d239bcSRobert Watson mac_ifnet_externalize_label(struct label *label, char *elements,
27683b7b0edSRobert Watson     char *outbuf, size_t outbuflen)
27769bbb5b1SRobert Watson {
27869bbb5b1SRobert Watson 	int error;
27969bbb5b1SRobert Watson 
280fa765671SRobert Watson 	MAC_POLICY_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen);
281f7b951a8SRobert Watson 
282f7b951a8SRobert Watson 	return (error);
283f7b951a8SRobert Watson }
284f7b951a8SRobert Watson 
285f7b951a8SRobert Watson static int
28630d239bcSRobert Watson mac_ifnet_internalize_label(struct label *label, char *string)
287f7b951a8SRobert Watson {
288f7b951a8SRobert Watson 	int error;
289f7b951a8SRobert Watson 
290fa765671SRobert Watson 	MAC_POLICY_INTERNALIZE(ifnet, label, string);
291f7b951a8SRobert Watson 
292f7b951a8SRobert Watson 	return (error);
293f7b951a8SRobert Watson }
294f7b951a8SRobert Watson 
29595fab37eSRobert Watson void
29630d239bcSRobert Watson mac_ifnet_create(struct ifnet *ifp)
29795fab37eSRobert Watson {
29895fab37eSRobert Watson 
29926ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
300fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_create, ifp, ifp->if_label);
30126ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
30295fab37eSRobert Watson }
30395fab37eSRobert Watson 
30495fab37eSRobert Watson void
30530d239bcSRobert Watson mac_bpfdesc_create(struct ucred *cred, struct bpf_d *d)
30695fab37eSRobert Watson {
30795fab37eSRobert Watson 
308fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_create, cred, d, d->bd_label);
30995fab37eSRobert Watson }
31095fab37eSRobert Watson 
31195fab37eSRobert Watson void
31230d239bcSRobert Watson mac_bpfdesc_create_mbuf(struct bpf_d *d, struct mbuf *m)
31395fab37eSRobert Watson {
31410eeb10cSRobert Watson 	struct label *label;
31510eeb10cSRobert Watson 
31626ae2b86SRobert Watson 	BPFD_LOCK_ASSERT(d);
317e33d9f29SRobert Watson 
31826ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
31995fab37eSRobert Watson 
320fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_create_mbuf, d, d->bd_label, m,
321fa765671SRobert Watson 	    label);
32295fab37eSRobert Watson }
32395fab37eSRobert Watson 
32495fab37eSRobert Watson void
32530d239bcSRobert Watson mac_ifnet_create_mbuf(struct ifnet *ifp, struct mbuf *m)
32695fab37eSRobert Watson {
32710eeb10cSRobert Watson 	struct label *label;
32810eeb10cSRobert Watson 
32926ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
33095fab37eSRobert Watson 
33126ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
332fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_create_mbuf, ifp, ifp->if_label, m,
333fa765671SRobert Watson 	    label);
33426ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
33595fab37eSRobert Watson }
33695fab37eSRobert Watson 
3372087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(bpfdesc_check_receive, "struct bpf_d *",
3382087a58cSRobert Watson     "struct ifnet *");
3392087a58cSRobert Watson 
34095fab37eSRobert Watson int
34130d239bcSRobert Watson mac_bpfdesc_check_receive(struct bpf_d *d, struct ifnet *ifp)
34295fab37eSRobert Watson {
34395fab37eSRobert Watson 	int error;
34495fab37eSRobert Watson 
34526ae2b86SRobert Watson 	BPFD_LOCK_ASSERT(d);
346e33d9f29SRobert Watson 
34726ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
348fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(bpfdesc_check_receive, d, d->bd_label, ifp,
34940202729SRobert Watson 	    ifp->if_label);
3502087a58cSRobert Watson 	MAC_CHECK_PROBE2(bpfdesc_check_receive, error, d, ifp);
35126ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
35295fab37eSRobert Watson 
35395fab37eSRobert Watson 	return (error);
35495fab37eSRobert Watson }
35595fab37eSRobert Watson 
3562087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(ifnet_check_transmit, "struct ifnet *",
3572087a58cSRobert Watson     "struct mbuf *");
3582087a58cSRobert Watson 
35995fab37eSRobert Watson int
36030d239bcSRobert Watson mac_ifnet_check_transmit(struct ifnet *ifp, struct mbuf *m)
36195fab37eSRobert Watson {
36210eeb10cSRobert Watson 	struct label *label;
36395fab37eSRobert Watson 	int error;
36495fab37eSRobert Watson 
36526ae2b86SRobert Watson 	M_ASSERTPKTHDR(m);
366225bff6fSRobert Watson 
36726ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
36895fab37eSRobert Watson 
36926ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
370fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(ifnet_check_transmit, ifp, ifp->if_label, m,
37140202729SRobert Watson 	    label);
3722087a58cSRobert Watson 	MAC_CHECK_PROBE2(ifnet_check_transmit, error, ifp, m);
37326ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
37495fab37eSRobert Watson 
37595fab37eSRobert Watson 	return (error);
37695fab37eSRobert Watson }
37795fab37eSRobert Watson 
37895fab37eSRobert Watson int
37930d239bcSRobert Watson mac_ifnet_ioctl_get(struct ucred *cred, struct ifreq *ifr,
38026ae2b86SRobert Watson     struct ifnet *ifp)
38195fab37eSRobert Watson {
382f7b951a8SRobert Watson 	char *elements, *buffer;
3832220907bSRobert Watson 	struct label *intlabel;
384f7b951a8SRobert Watson 	struct mac mac;
38595fab37eSRobert Watson 	int error;
38695fab37eSRobert Watson 
3876356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_IFNET))
3886356dba0SRobert Watson 		return (EINVAL);
3896356dba0SRobert Watson 
390f7b951a8SRobert Watson 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
39195fab37eSRobert Watson 	if (error)
39295fab37eSRobert Watson 		return (error);
39395fab37eSRobert Watson 
394f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
395f7b951a8SRobert Watson 	if (error)
396f7b951a8SRobert Watson 		return (error);
397f7b951a8SRobert Watson 
398a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
399f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
400f7b951a8SRobert Watson 	if (error) {
401f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
402f7b951a8SRobert Watson 		return (error);
403f7b951a8SRobert Watson 	}
404f7b951a8SRobert Watson 
405a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
4062220907bSRobert Watson 	intlabel = mac_ifnet_label_alloc();
40726ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
40830d239bcSRobert Watson 	mac_ifnet_copy_label(ifp->if_label, intlabel);
40926ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
41030d239bcSRobert Watson 	error = mac_ifnet_externalize_label(intlabel, elements, buffer,
4118f3476b3SRobert Watson 	    mac.m_buflen);
4122220907bSRobert Watson 	mac_ifnet_label_free(intlabel);
413f7b951a8SRobert Watson 	if (error == 0)
414f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
415f7b951a8SRobert Watson 
416f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
417f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
418f7b951a8SRobert Watson 
419f7b951a8SRobert Watson 	return (error);
42095fab37eSRobert Watson }
42195fab37eSRobert Watson 
42295fab37eSRobert Watson int
42330d239bcSRobert Watson mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp)
42495fab37eSRobert Watson {
425eca8a663SRobert Watson 	struct label *intlabel;
426f7b951a8SRobert Watson 	struct mac mac;
427f7b951a8SRobert Watson 	char *buffer;
42895fab37eSRobert Watson 	int error;
42995fab37eSRobert Watson 
4306356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_IFNET))
4316356dba0SRobert Watson 		return (EINVAL);
4326356dba0SRobert Watson 
433f7b951a8SRobert Watson 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
43495fab37eSRobert Watson 	if (error)
43595fab37eSRobert Watson 		return (error);
43695fab37eSRobert Watson 
437f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
43895fab37eSRobert Watson 	if (error)
43995fab37eSRobert Watson 		return (error);
44095fab37eSRobert Watson 
441a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
442f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
443f7b951a8SRobert Watson 	if (error) {
444f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
445f7b951a8SRobert Watson 		return (error);
446f7b951a8SRobert Watson 	}
447f7b951a8SRobert Watson 
448eca8a663SRobert Watson 	intlabel = mac_ifnet_label_alloc();
44930d239bcSRobert Watson 	error = mac_ifnet_internalize_label(intlabel, buffer);
450f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
451f7b951a8SRobert Watson 	if (error) {
452eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
453f7b951a8SRobert Watson 		return (error);
454f7b951a8SRobert Watson 	}
455f7b951a8SRobert Watson 
45695fab37eSRobert Watson 	/*
457acd3428bSRobert Watson 	 * XXX: Note that this is a redundant privilege check, since policies
458e678cce9SRobert Watson 	 * impose this check themselves if required by the policy
459acd3428bSRobert Watson 	 * Eventually, this should go away.
46095fab37eSRobert Watson 	 */
461acd3428bSRobert Watson 	error = priv_check_cred(cred, PRIV_NET_SETIFMAC, 0);
462f7b951a8SRobert Watson 	if (error) {
463eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
464f7b951a8SRobert Watson 		return (error);
465f7b951a8SRobert Watson 	}
46695fab37eSRobert Watson 
46726ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
468fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(ifnet_check_relabel, cred, ifp,
469fa765671SRobert Watson 	    ifp->if_label, intlabel);
470f7b951a8SRobert Watson 	if (error) {
47126ae2b86SRobert Watson 		MAC_IFNET_UNLOCK(ifp);
472eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
473f7b951a8SRobert Watson 		return (error);
474f7b951a8SRobert Watson 	}
47595fab37eSRobert Watson 
476fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(ifnet_relabel, cred, ifp, ifp->if_label,
47740202729SRobert Watson 	    intlabel);
47826ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
47995fab37eSRobert Watson 
480eca8a663SRobert Watson 	mac_ifnet_label_free(intlabel);
481f7b951a8SRobert Watson 	return (0);
48295fab37eSRobert Watson }
483