xref: /freebsd/sys/security/mac/mac_net.c (revision 6356dba0b403daa023dec24559ab1f8e602e4f14)
17bc82500SRobert Watson /*-
2f6a41092SRobert Watson  * Copyright (c) 1999-2002 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  *
207bc82500SRobert Watson  * Redistribution and use in source and binary forms, with or without
217bc82500SRobert Watson  * modification, are permitted provided that the following conditions
227bc82500SRobert Watson  * are met:
237bc82500SRobert Watson  * 1. Redistributions of source code must retain the above copyright
247bc82500SRobert Watson  *    notice, this list of conditions and the following disclaimer.
257bc82500SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
267bc82500SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
277bc82500SRobert Watson  *    documentation and/or other materials provided with the distribution.
287bc82500SRobert Watson  *
297bc82500SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
307bc82500SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
317bc82500SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
327bc82500SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
337bc82500SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
347bc82500SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
357bc82500SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
367bc82500SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
377bc82500SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
387bc82500SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
397bc82500SRobert Watson  * SUCH DAMAGE.
407bc82500SRobert Watson  */
41677b542eSDavid E. O'Brien 
42677b542eSDavid E. O'Brien #include <sys/cdefs.h>
43677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
44677b542eSDavid E. O'Brien 
457bc82500SRobert Watson #include "opt_mac.h"
46f9d0d524SRobert Watson 
477bc82500SRobert Watson #include <sys/param.h>
4895fab37eSRobert Watson #include <sys/kernel.h>
4995fab37eSRobert Watson #include <sys/lock.h>
50b656366bSBruce Evans #include <sys/malloc.h>
5195fab37eSRobert Watson #include <sys/mutex.h>
5295fab37eSRobert Watson #include <sys/mac.h>
53acd3428bSRobert Watson #include <sys/priv.h>
54f51e5803SRobert Watson #include <sys/sbuf.h>
5595fab37eSRobert Watson #include <sys/systm.h>
5695fab37eSRobert Watson #include <sys/mount.h>
5795fab37eSRobert Watson #include <sys/file.h>
5895fab37eSRobert Watson #include <sys/namei.h>
59a557af22SRobert Watson #include <sys/protosw.h>
6095fab37eSRobert Watson #include <sys/socket.h>
6195fab37eSRobert Watson #include <sys/socketvar.h>
6295fab37eSRobert Watson #include <sys/sysctl.h>
6395fab37eSRobert Watson 
6495fab37eSRobert Watson #include <net/bpfdesc.h>
6595fab37eSRobert Watson #include <net/if.h>
6695fab37eSRobert Watson #include <net/if_var.h>
6795fab37eSRobert Watson 
68aed55708SRobert Watson #include <security/mac/mac_framework.h>
6928e65e3dSRobert Watson #include <security/mac/mac_internal.h>
700efd6615SRobert Watson #include <security/mac/mac_policy.h>
71a3df768bSRobert Watson 
72c66b4d8dSRobert Watson /*
73e678cce9SRobert Watson  * XXXRW: struct ifnet locking is incomplete in the network code, so we use
74e678cce9SRobert Watson  * our own global mutex for struct ifnet.  Non-ideal, but should help in the
75e678cce9SRobert Watson  * SMP environment.
762220907bSRobert Watson  */
77b9b0dac3SRobert Watson struct mtx mac_ifnet_mtx;
782220907bSRobert Watson MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF);
792220907bSRobert Watson 
80e678cce9SRobert Watson /*
81e678cce9SRobert Watson  * Retrieve the label associated with an mbuf by searching for the tag.
82e678cce9SRobert Watson  * Depending on the value of mac_labelmbufs, it's possible that a label will
83e678cce9SRobert Watson  * not be present, in which case NULL is returned.  Policies must handle the
84e678cce9SRobert Watson  * possibility of an mbuf not having label storage if they do not enforce
85e678cce9SRobert Watson  * early loading.
86e678cce9SRobert Watson  */
87c66b4d8dSRobert Watson struct label *
8826ae2b86SRobert Watson mac_mbuf_to_label(struct mbuf *m)
8910eeb10cSRobert Watson {
90225bff6fSRobert Watson 	struct m_tag *tag;
9110eeb10cSRobert Watson 	struct label *label;
9210eeb10cSRobert Watson 
9326ae2b86SRobert Watson 	if (m == NULL)
94583284e1SRobert Watson 		return (NULL);
9526ae2b86SRobert Watson 	tag = m_tag_find(m, PACKET_TAG_MACLABEL, NULL);
96583284e1SRobert Watson 	if (tag == NULL)
97583284e1SRobert Watson 		return (NULL);
98225bff6fSRobert Watson 	label = (struct label *)(tag+1);
9910eeb10cSRobert Watson 	return (label);
10010eeb10cSRobert Watson }
10110eeb10cSRobert Watson 
102eca8a663SRobert Watson static struct label *
103eca8a663SRobert Watson mac_bpfdesc_label_alloc(void)
104eca8a663SRobert Watson {
105eca8a663SRobert Watson 	struct label *label;
106eca8a663SRobert Watson 
107eca8a663SRobert Watson 	label = mac_labelzone_alloc(M_WAITOK);
10830d239bcSRobert Watson 	MAC_PERFORM(bpfdesc_init_label, label);
109eca8a663SRobert Watson 	return (label);
110eca8a663SRobert Watson }
111eca8a663SRobert Watson 
11208bcdc58SRobert Watson void
11330d239bcSRobert Watson mac_bpfdesc_init(struct bpf_d *d)
11408bcdc58SRobert Watson {
11508bcdc58SRobert Watson 
1166356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_BPFDESC)
11726ae2b86SRobert Watson 		d->bd_label = mac_bpfdesc_label_alloc();
1186356dba0SRobert Watson 	else
1196356dba0SRobert Watson 		d->bd_label = NULL;
12008bcdc58SRobert Watson }
12108bcdc58SRobert Watson 
122eca8a663SRobert Watson static struct label *
123eca8a663SRobert Watson mac_ifnet_label_alloc(void)
124f7b951a8SRobert Watson {
125eca8a663SRobert Watson 	struct label *label;
126f7b951a8SRobert Watson 
127eca8a663SRobert Watson 	label = mac_labelzone_alloc(M_WAITOK);
12830d239bcSRobert Watson 	MAC_PERFORM(ifnet_init_label, label);
129eca8a663SRobert Watson 	return (label);
130f7b951a8SRobert Watson }
131f7b951a8SRobert Watson 
13208bcdc58SRobert Watson void
13330d239bcSRobert Watson mac_ifnet_init(struct ifnet *ifp)
13408bcdc58SRobert Watson {
13508bcdc58SRobert Watson 
1366356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_IFNET)
137eca8a663SRobert Watson 		ifp->if_label = mac_ifnet_label_alloc();
1386356dba0SRobert Watson 	else
1396356dba0SRobert Watson 		ifp->if_label = NULL;
140eca8a663SRobert Watson }
141eca8a663SRobert Watson 
14287807196SRobert Watson int
14330d239bcSRobert Watson mac_mbuf_tag_init(struct m_tag *tag, int flag)
14408bcdc58SRobert Watson {
145225bff6fSRobert Watson 	struct label *label;
1466d1a6a9aSRobert Watson 	int error;
14756c15412SRobert Watson 
148225bff6fSRobert Watson 	label = (struct label *) (tag + 1);
149225bff6fSRobert Watson 	mac_init_label(label);
15008bcdc58SRobert Watson 
15130d239bcSRobert Watson 	MAC_CHECK(mbuf_init_label, label, flag);
15256c15412SRobert Watson 	if (error) {
15330d239bcSRobert Watson 		MAC_PERFORM(mbuf_destroy_label, label);
154225bff6fSRobert Watson 		mac_destroy_label(label);
15556c15412SRobert Watson 	}
15656c15412SRobert Watson 	return (error);
15708bcdc58SRobert Watson }
15808bcdc58SRobert Watson 
159225bff6fSRobert Watson int
16030d239bcSRobert Watson mac_mbuf_init(struct mbuf *m, int flag)
161225bff6fSRobert Watson {
162225bff6fSRobert Watson 	struct m_tag *tag;
163225bff6fSRobert Watson 	int error;
164225bff6fSRobert Watson 
165225bff6fSRobert Watson 	M_ASSERTPKTHDR(m);
166225bff6fSRobert Watson 
1676356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_MBUF) {
168225bff6fSRobert Watson 		tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label),
169225bff6fSRobert Watson 		    flag);
170225bff6fSRobert Watson 		if (tag == NULL)
171225bff6fSRobert Watson 			return (ENOMEM);
17230d239bcSRobert Watson 		error = mac_mbuf_tag_init(tag, flag);
173225bff6fSRobert Watson 		if (error) {
174225bff6fSRobert Watson 			m_tag_free(tag);
175225bff6fSRobert Watson 			return (error);
176225bff6fSRobert Watson 		}
177225bff6fSRobert Watson 		m_tag_prepend(m, tag);
1786356dba0SRobert Watson 	}
179225bff6fSRobert Watson 	return (0);
180225bff6fSRobert Watson }
181225bff6fSRobert Watson 
182eca8a663SRobert Watson static void
183eca8a663SRobert Watson mac_bpfdesc_label_free(struct label *label)
184eca8a663SRobert Watson {
18583985c26SRobert Watson 
18630d239bcSRobert Watson 	MAC_PERFORM(bpfdesc_destroy_label, label);
187eca8a663SRobert Watson 	mac_labelzone_free(label);
18887807196SRobert Watson }
18987807196SRobert Watson 
190763bbd2fSRobert Watson void
19130d239bcSRobert Watson mac_bpfdesc_destroy(struct bpf_d *d)
19208bcdc58SRobert Watson {
19308bcdc58SRobert Watson 
1946356dba0SRobert Watson 	if (d->bd_label != NULL) {
19526ae2b86SRobert Watson 		mac_bpfdesc_label_free(d->bd_label);
19626ae2b86SRobert Watson 		d->bd_label = NULL;
19708bcdc58SRobert Watson 	}
1986356dba0SRobert Watson }
19908bcdc58SRobert Watson 
200f7b951a8SRobert Watson static void
201eca8a663SRobert Watson mac_ifnet_label_free(struct label *label)
202f7b951a8SRobert Watson {
203f7b951a8SRobert Watson 
20430d239bcSRobert Watson 	MAC_PERFORM(ifnet_destroy_label, label);
205eca8a663SRobert Watson 	mac_labelzone_free(label);
206f7b951a8SRobert Watson }
207f7b951a8SRobert Watson 
20887807196SRobert Watson void
20930d239bcSRobert Watson mac_ifnet_destroy(struct ifnet *ifp)
21087807196SRobert Watson {
21187807196SRobert Watson 
2126356dba0SRobert Watson 	if (ifp->if_label != NULL) {
213eca8a663SRobert Watson 		mac_ifnet_label_free(ifp->if_label);
214eca8a663SRobert Watson 		ifp->if_label = NULL;
215eca8a663SRobert Watson 	}
2166356dba0SRobert Watson }
217eca8a663SRobert Watson 
21887807196SRobert Watson void
21930d239bcSRobert Watson mac_mbuf_tag_destroy(struct m_tag *tag)
22087807196SRobert Watson {
221225bff6fSRobert Watson 	struct label *label;
22287807196SRobert Watson 
223225bff6fSRobert Watson 	label = (struct label *)(tag+1);
224225bff6fSRobert Watson 
22530d239bcSRobert Watson 	MAC_PERFORM(mbuf_destroy_label, label);
226225bff6fSRobert Watson 	mac_destroy_label(label);
22708bcdc58SRobert Watson }
22808bcdc58SRobert Watson 
229e678cce9SRobert Watson /*
23030d239bcSRobert Watson  * mac_mbuf_tag_copy is called when an mbuf header is duplicated, in which
231e678cce9SRobert Watson  * case the labels must also be duplicated.
232e678cce9SRobert Watson  */
233b0323ea3SRobert Watson void
23430d239bcSRobert Watson mac_mbuf_tag_copy(struct m_tag *src, struct m_tag *dest)
235225bff6fSRobert Watson {
236225bff6fSRobert Watson 	struct label *src_label, *dest_label;
237225bff6fSRobert Watson 
238225bff6fSRobert Watson 	src_label = (struct label *)(src+1);
239225bff6fSRobert Watson 	dest_label = (struct label *)(dest+1);
240225bff6fSRobert Watson 
241225bff6fSRobert Watson 	/*
24230d239bcSRobert Watson 	 * mac_mbuf_tag_init() is called on the target tag in m_tag_copy(),
243e678cce9SRobert Watson 	 * so we don't need to call it here.
244225bff6fSRobert Watson 	 */
24530d239bcSRobert Watson 	MAC_PERFORM(mbuf_copy_label, src_label, dest_label);
246225bff6fSRobert Watson }
247225bff6fSRobert Watson 
2483c308b09SRobert Watson void
24930d239bcSRobert Watson mac_mbuf_copy(struct mbuf *m_from, struct mbuf *m_to)
2503c308b09SRobert Watson {
2513c308b09SRobert Watson 	struct label *src_label, *dest_label;
2523c308b09SRobert Watson 
2533c308b09SRobert Watson 	src_label = mac_mbuf_to_label(m_from);
2543c308b09SRobert Watson 	dest_label = mac_mbuf_to_label(m_to);
2553c308b09SRobert Watson 
25630d239bcSRobert Watson 	MAC_PERFORM(mbuf_copy_label, src_label, dest_label);
2573c308b09SRobert Watson }
2583c308b09SRobert Watson 
2592220907bSRobert Watson static void
26030d239bcSRobert Watson mac_ifnet_copy_label(struct label *src, struct label *dest)
2612220907bSRobert Watson {
2622220907bSRobert Watson 
26330d239bcSRobert Watson 	MAC_PERFORM(ifnet_copy_label, src, dest);
2642220907bSRobert Watson }
2652220907bSRobert Watson 
26669bbb5b1SRobert Watson static int
26730d239bcSRobert Watson mac_ifnet_externalize_label(struct label *label, char *elements,
26883b7b0edSRobert Watson     char *outbuf, size_t outbuflen)
26969bbb5b1SRobert Watson {
27069bbb5b1SRobert Watson 	int error;
27169bbb5b1SRobert Watson 
272da77b2faSRobert Watson 	MAC_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen);
273f7b951a8SRobert Watson 
274f7b951a8SRobert Watson 	return (error);
275f7b951a8SRobert Watson }
276f7b951a8SRobert Watson 
277f7b951a8SRobert Watson static int
27830d239bcSRobert Watson mac_ifnet_internalize_label(struct label *label, char *string)
279f7b951a8SRobert Watson {
280f7b951a8SRobert Watson 	int error;
281f7b951a8SRobert Watson 
282da77b2faSRobert Watson 	MAC_INTERNALIZE(ifnet, label, string);
283f7b951a8SRobert Watson 
284f7b951a8SRobert Watson 	return (error);
285f7b951a8SRobert Watson }
286f7b951a8SRobert Watson 
28795fab37eSRobert Watson void
28830d239bcSRobert Watson mac_ifnet_create(struct ifnet *ifp)
28995fab37eSRobert Watson {
29095fab37eSRobert Watson 
29126ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
29230d239bcSRobert Watson 	MAC_PERFORM(ifnet_create, ifp, ifp->if_label);
29326ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
29495fab37eSRobert Watson }
29595fab37eSRobert Watson 
29695fab37eSRobert Watson void
29730d239bcSRobert Watson mac_bpfdesc_create(struct ucred *cred, struct bpf_d *d)
29895fab37eSRobert Watson {
29995fab37eSRobert Watson 
30030d239bcSRobert Watson 	MAC_PERFORM(bpfdesc_create, cred, d, d->bd_label);
30195fab37eSRobert Watson }
30295fab37eSRobert Watson 
30395fab37eSRobert Watson void
30430d239bcSRobert Watson mac_bpfdesc_create_mbuf(struct bpf_d *d, struct mbuf *m)
30595fab37eSRobert Watson {
30610eeb10cSRobert Watson 	struct label *label;
30710eeb10cSRobert Watson 
30826ae2b86SRobert Watson 	BPFD_LOCK_ASSERT(d);
309e33d9f29SRobert Watson 
31026ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
31195fab37eSRobert Watson 
31230d239bcSRobert Watson 	MAC_PERFORM(bpfdesc_create_mbuf, d, d->bd_label, m, label);
31395fab37eSRobert Watson }
31495fab37eSRobert Watson 
31595fab37eSRobert Watson void
31630d239bcSRobert Watson mac_ifnet_create_mbuf(struct ifnet *ifp, struct mbuf *m)
31795fab37eSRobert Watson {
31810eeb10cSRobert Watson 	struct label *label;
31910eeb10cSRobert Watson 
32026ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
32195fab37eSRobert Watson 
32226ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
32330d239bcSRobert Watson 	MAC_PERFORM(ifnet_create_mbuf, ifp, ifp->if_label, m, label);
32426ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
32595fab37eSRobert Watson }
32695fab37eSRobert Watson 
32795fab37eSRobert Watson int
32830d239bcSRobert Watson mac_bpfdesc_check_receive(struct bpf_d *d, struct ifnet *ifp)
32995fab37eSRobert Watson {
33095fab37eSRobert Watson 	int error;
33195fab37eSRobert Watson 
33226ae2b86SRobert Watson 	BPFD_LOCK_ASSERT(d);
333e33d9f29SRobert Watson 
33426ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
33530d239bcSRobert Watson 	MAC_CHECK(bpfdesc_check_receive, d, d->bd_label, ifp, ifp->if_label);
33626ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
33795fab37eSRobert Watson 
33895fab37eSRobert Watson 	return (error);
33995fab37eSRobert Watson }
34095fab37eSRobert Watson 
34195fab37eSRobert Watson int
34230d239bcSRobert Watson mac_ifnet_check_transmit(struct ifnet *ifp, struct mbuf *m)
34395fab37eSRobert Watson {
34410eeb10cSRobert Watson 	struct label *label;
34595fab37eSRobert Watson 	int error;
34695fab37eSRobert Watson 
34726ae2b86SRobert Watson 	M_ASSERTPKTHDR(m);
348225bff6fSRobert Watson 
34926ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
35095fab37eSRobert Watson 
35126ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
35230d239bcSRobert Watson 	MAC_CHECK(ifnet_check_transmit, ifp, ifp->if_label, m, label);
35326ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
35495fab37eSRobert Watson 
35595fab37eSRobert Watson 	return (error);
35695fab37eSRobert Watson }
35795fab37eSRobert Watson 
35895fab37eSRobert Watson int
35930d239bcSRobert Watson mac_ifnet_ioctl_get(struct ucred *cred, struct ifreq *ifr,
36026ae2b86SRobert Watson     struct ifnet *ifp)
36195fab37eSRobert Watson {
362f7b951a8SRobert Watson 	char *elements, *buffer;
3632220907bSRobert Watson 	struct label *intlabel;
364f7b951a8SRobert Watson 	struct mac mac;
36595fab37eSRobert Watson 	int error;
36695fab37eSRobert Watson 
3676356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_IFNET))
3686356dba0SRobert Watson 		return (EINVAL);
3696356dba0SRobert Watson 
370f7b951a8SRobert Watson 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
37195fab37eSRobert Watson 	if (error)
37295fab37eSRobert Watson 		return (error);
37395fab37eSRobert Watson 
374f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
375f7b951a8SRobert Watson 	if (error)
376f7b951a8SRobert Watson 		return (error);
377f7b951a8SRobert Watson 
378a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
379f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
380f7b951a8SRobert Watson 	if (error) {
381f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
382f7b951a8SRobert Watson 		return (error);
383f7b951a8SRobert Watson 	}
384f7b951a8SRobert Watson 
385a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
3862220907bSRobert Watson 	intlabel = mac_ifnet_label_alloc();
38726ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
38830d239bcSRobert Watson 	mac_ifnet_copy_label(ifp->if_label, intlabel);
38926ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
39030d239bcSRobert Watson 	error = mac_ifnet_externalize_label(intlabel, elements, buffer,
3918f3476b3SRobert Watson 	    mac.m_buflen);
3922220907bSRobert Watson 	mac_ifnet_label_free(intlabel);
393f7b951a8SRobert Watson 	if (error == 0)
394f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
395f7b951a8SRobert Watson 
396f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
397f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
398f7b951a8SRobert Watson 
399f7b951a8SRobert Watson 	return (error);
40095fab37eSRobert Watson }
40195fab37eSRobert Watson 
40295fab37eSRobert Watson int
40330d239bcSRobert Watson mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp)
40495fab37eSRobert Watson {
405eca8a663SRobert Watson 	struct label *intlabel;
406f7b951a8SRobert Watson 	struct mac mac;
407f7b951a8SRobert Watson 	char *buffer;
40895fab37eSRobert Watson 	int error;
40995fab37eSRobert Watson 
4106356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_IFNET))
4116356dba0SRobert Watson 		return (EINVAL);
4126356dba0SRobert Watson 
413f7b951a8SRobert Watson 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
41495fab37eSRobert Watson 	if (error)
41595fab37eSRobert Watson 		return (error);
41695fab37eSRobert Watson 
417f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
41895fab37eSRobert Watson 	if (error)
41995fab37eSRobert Watson 		return (error);
42095fab37eSRobert Watson 
421a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
422f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
423f7b951a8SRobert Watson 	if (error) {
424f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
425f7b951a8SRobert Watson 		return (error);
426f7b951a8SRobert Watson 	}
427f7b951a8SRobert Watson 
428eca8a663SRobert Watson 	intlabel = mac_ifnet_label_alloc();
42930d239bcSRobert Watson 	error = mac_ifnet_internalize_label(intlabel, buffer);
430f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
431f7b951a8SRobert Watson 	if (error) {
432eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
433f7b951a8SRobert Watson 		return (error);
434f7b951a8SRobert Watson 	}
435f7b951a8SRobert Watson 
43695fab37eSRobert Watson 	/*
437acd3428bSRobert Watson 	 * XXX: Note that this is a redundant privilege check, since policies
438e678cce9SRobert Watson 	 * impose this check themselves if required by the policy
439acd3428bSRobert Watson 	 * Eventually, this should go away.
44095fab37eSRobert Watson 	 */
441acd3428bSRobert Watson 	error = priv_check_cred(cred, PRIV_NET_SETIFMAC, 0);
442f7b951a8SRobert Watson 	if (error) {
443eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
444f7b951a8SRobert Watson 		return (error);
445f7b951a8SRobert Watson 	}
44695fab37eSRobert Watson 
44726ae2b86SRobert Watson 	MAC_IFNET_LOCK(ifp);
44830d239bcSRobert Watson 	MAC_CHECK(ifnet_check_relabel, cred, ifp, ifp->if_label, intlabel);
449f7b951a8SRobert Watson 	if (error) {
45026ae2b86SRobert Watson 		MAC_IFNET_UNLOCK(ifp);
451eca8a663SRobert Watson 		mac_ifnet_label_free(intlabel);
452f7b951a8SRobert Watson 		return (error);
453f7b951a8SRobert Watson 	}
45495fab37eSRobert Watson 
45530d239bcSRobert Watson 	MAC_PERFORM(ifnet_relabel, cred, ifp, ifp->if_label, intlabel);
45626ae2b86SRobert Watson 	MAC_IFNET_UNLOCK(ifp);
45795fab37eSRobert Watson 
458eca8a663SRobert Watson 	mac_ifnet_label_free(intlabel);
459f7b951a8SRobert Watson 	return (0);
46095fab37eSRobert Watson }
461