xref: /freebsd/sys/security/mac/mac_net.c (revision acd3428b7d3e94cef0e1881c868cb4b131d4ff41)
1 /*-
2  * Copyright (c) 1999-2002 Robert N. M. Watson
3  * Copyright (c) 2001 Ilmar S. Habibulin
4  * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
5  * All rights reserved.
6  *
7  * This software was developed by Robert Watson and Ilmar Habibulin for the
8  * TrustedBSD Project.
9  *
10  * This software was developed for the FreeBSD Project in part by Network
11  * Associates Laboratories, the Security Research Division of Network
12  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13  * as part of the DARPA CHATS research program.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39 
40 #include "opt_mac.h"
41 
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/mutex.h>
47 #include <sys/mac.h>
48 #include <sys/priv.h>
49 #include <sys/sbuf.h>
50 #include <sys/systm.h>
51 #include <sys/mount.h>
52 #include <sys/file.h>
53 #include <sys/namei.h>
54 #include <sys/protosw.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/sysctl.h>
58 
59 #include <sys/mac_policy.h>
60 
61 #include <net/bpfdesc.h>
62 #include <net/if.h>
63 #include <net/if_var.h>
64 
65 #include <security/mac/mac_framework.h>
66 #include <security/mac/mac_internal.h>
67 
68 /*
69  * mac_enforce_network is used by IPv4 and IPv6 checks, and so must
70  * be non-static for now.
71  */
72 int	mac_enforce_network = 1;
73 SYSCTL_INT(_security_mac, OID_AUTO, enforce_network, CTLFLAG_RW,
74     &mac_enforce_network, 0, "Enforce MAC policy on network packets");
75 TUNABLE_INT("security.mac.enforce_network", &mac_enforce_network);
76 
77 /*
78  * XXXRW: struct ifnet locking is incomplete in the network code, so we
79  * use our own global mutex for struct ifnet.  Non-ideal, but should help
80  * in the SMP environment.
81  */
82 static struct mtx mac_ifnet_mtx;
83 MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF);
84 #define	MAC_IFNET_LOCK(ifp)	mtx_lock(&mac_ifnet_mtx)
85 #define	MAC_IFNET_UNLOCK(ifp)	mtx_unlock(&mac_ifnet_mtx)
86 
87 struct label *
88 mac_mbuf_to_label(struct mbuf *mbuf)
89 {
90 	struct m_tag *tag;
91 	struct label *label;
92 
93 	if (mbuf == NULL)
94 		return (NULL);
95 	tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL);
96 	if (tag == NULL)
97 		return (NULL);
98 	label = (struct label *)(tag+1);
99 	return (label);
100 }
101 
102 static struct label *
103 mac_bpfdesc_label_alloc(void)
104 {
105 	struct label *label;
106 
107 	label = mac_labelzone_alloc(M_WAITOK);
108 	MAC_PERFORM(init_bpfdesc_label, label);
109 	return (label);
110 }
111 
112 void
113 mac_init_bpfdesc(struct bpf_d *bpf_d)
114 {
115 
116 	bpf_d->bd_label = mac_bpfdesc_label_alloc();
117 }
118 
119 static struct label *
120 mac_ifnet_label_alloc(void)
121 {
122 	struct label *label;
123 
124 	label = mac_labelzone_alloc(M_WAITOK);
125 	MAC_PERFORM(init_ifnet_label, label);
126 	return (label);
127 }
128 
129 void
130 mac_init_ifnet(struct ifnet *ifp)
131 {
132 
133 	ifp->if_label = mac_ifnet_label_alloc();
134 }
135 
136 int
137 mac_init_mbuf_tag(struct m_tag *tag, int flag)
138 {
139 	struct label *label;
140 	int error;
141 
142 	label = (struct label *) (tag + 1);
143 	mac_init_label(label);
144 
145 	MAC_CHECK(init_mbuf_label, label, flag);
146 	if (error) {
147 		MAC_PERFORM(destroy_mbuf_label, label);
148 		mac_destroy_label(label);
149 	}
150 	return (error);
151 }
152 
153 int
154 mac_init_mbuf(struct mbuf *m, int flag)
155 {
156 	struct m_tag *tag;
157 	int error;
158 
159 	M_ASSERTPKTHDR(m);
160 
161 #ifndef MAC_ALWAYS_LABEL_MBUF
162 	/*
163 	 * If conditionally allocating mbuf labels, don't allocate unless
164 	 * they are required.
165 	 */
166 	if (!mac_labelmbufs)
167 		return (0);
168 #endif
169 	tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label),
170 	    flag);
171 	if (tag == NULL)
172 		return (ENOMEM);
173 	error = mac_init_mbuf_tag(tag, flag);
174 	if (error) {
175 		m_tag_free(tag);
176 		return (error);
177 	}
178 	m_tag_prepend(m, tag);
179 	return (0);
180 }
181 
182 static void
183 mac_bpfdesc_label_free(struct label *label)
184 {
185 
186 	MAC_PERFORM(destroy_bpfdesc_label, label);
187 	mac_labelzone_free(label);
188 }
189 
190 void
191 mac_destroy_bpfdesc(struct bpf_d *bpf_d)
192 {
193 
194 	mac_bpfdesc_label_free(bpf_d->bd_label);
195 	bpf_d->bd_label = NULL;
196 }
197 
198 static void
199 mac_ifnet_label_free(struct label *label)
200 {
201 
202 	MAC_PERFORM(destroy_ifnet_label, label);
203 	mac_labelzone_free(label);
204 }
205 
206 void
207 mac_destroy_ifnet(struct ifnet *ifp)
208 {
209 
210 	mac_ifnet_label_free(ifp->if_label);
211 	ifp->if_label = NULL;
212 }
213 
214 void
215 mac_destroy_mbuf_tag(struct m_tag *tag)
216 {
217 	struct label *label;
218 
219 	label = (struct label *)(tag+1);
220 
221 	MAC_PERFORM(destroy_mbuf_label, label);
222 	mac_destroy_label(label);
223 }
224 
225 void
226 mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest)
227 {
228 	struct label *src_label, *dest_label;
229 
230 	src_label = (struct label *)(src+1);
231 	dest_label = (struct label *)(dest+1);
232 
233 	/*
234 	 * mac_init_mbuf_tag() is called on the target tag in
235 	 * m_tag_copy(), so we don't need to call it here.
236 	 */
237 	MAC_PERFORM(copy_mbuf_label, src_label, dest_label);
238 }
239 
240 void
241 mac_copy_mbuf(struct mbuf *m_from, struct mbuf *m_to)
242 {
243 	struct label *src_label, *dest_label;
244 
245 	src_label = mac_mbuf_to_label(m_from);
246 	dest_label = mac_mbuf_to_label(m_to);
247 
248 	MAC_PERFORM(copy_mbuf_label, src_label, dest_label);
249 }
250 
251 static void
252 mac_copy_ifnet_label(struct label *src, struct label *dest)
253 {
254 
255 	MAC_PERFORM(copy_ifnet_label, src, dest);
256 }
257 
258 static int
259 mac_externalize_ifnet_label(struct label *label, char *elements,
260     char *outbuf, size_t outbuflen)
261 {
262 	int error;
263 
264 	MAC_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen);
265 
266 	return (error);
267 }
268 
269 static int
270 mac_internalize_ifnet_label(struct label *label, char *string)
271 {
272 	int error;
273 
274 	MAC_INTERNALIZE(ifnet, label, string);
275 
276 	return (error);
277 }
278 
279 void
280 mac_create_ifnet(struct ifnet *ifnet)
281 {
282 
283 	MAC_IFNET_LOCK(ifnet);
284 	MAC_PERFORM(create_ifnet, ifnet, ifnet->if_label);
285 	MAC_IFNET_UNLOCK(ifnet);
286 }
287 
288 void
289 mac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d)
290 {
291 
292 	MAC_PERFORM(create_bpfdesc, cred, bpf_d, bpf_d->bd_label);
293 }
294 
295 void
296 mac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct mbuf *mbuf)
297 {
298 	struct label *label;
299 
300 	BPFD_LOCK_ASSERT(bpf_d);
301 
302 	label = mac_mbuf_to_label(mbuf);
303 
304 	MAC_PERFORM(create_mbuf_from_bpfdesc, bpf_d, bpf_d->bd_label, mbuf,
305 	    label);
306 }
307 
308 void
309 mac_create_mbuf_linklayer(struct ifnet *ifnet, struct mbuf *mbuf)
310 {
311 	struct label *label;
312 
313 	label = mac_mbuf_to_label(mbuf);
314 
315 	MAC_IFNET_LOCK(ifnet);
316 	MAC_PERFORM(create_mbuf_linklayer, ifnet, ifnet->if_label, mbuf,
317 	    label);
318 	MAC_IFNET_UNLOCK(ifnet);
319 }
320 
321 void
322 mac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct mbuf *mbuf)
323 {
324 	struct label *label;
325 
326 	label = mac_mbuf_to_label(mbuf);
327 
328 	MAC_IFNET_LOCK(ifnet);
329 	MAC_PERFORM(create_mbuf_from_ifnet, ifnet, ifnet->if_label, mbuf,
330 	    label);
331 	MAC_IFNET_UNLOCK(ifnet);
332 }
333 
334 void
335 mac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct ifnet *ifnet,
336     struct mbuf *newmbuf)
337 {
338 	struct label *oldmbuflabel, *newmbuflabel;
339 
340 	oldmbuflabel = mac_mbuf_to_label(oldmbuf);
341 	newmbuflabel = mac_mbuf_to_label(newmbuf);
342 
343 	MAC_IFNET_LOCK(ifnet);
344 	MAC_PERFORM(create_mbuf_multicast_encap, oldmbuf, oldmbuflabel,
345 	    ifnet, ifnet->if_label, newmbuf, newmbuflabel);
346 	MAC_IFNET_UNLOCK(ifnet);
347 }
348 
349 void
350 mac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct mbuf *newmbuf)
351 {
352 	struct label *oldmbuflabel, *newmbuflabel;
353 
354 	oldmbuflabel = mac_mbuf_to_label(oldmbuf);
355 	newmbuflabel = mac_mbuf_to_label(newmbuf);
356 
357 	MAC_PERFORM(create_mbuf_netlayer, oldmbuf, oldmbuflabel, newmbuf,
358 	    newmbuflabel);
359 }
360 
361 int
362 mac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct ifnet *ifnet)
363 {
364 	int error;
365 
366 	BPFD_LOCK_ASSERT(bpf_d);
367 
368 	if (!mac_enforce_network)
369 		return (0);
370 
371 	MAC_IFNET_LOCK(ifnet);
372 	MAC_CHECK(check_bpfdesc_receive, bpf_d, bpf_d->bd_label, ifnet,
373 	    ifnet->if_label);
374 	MAC_IFNET_UNLOCK(ifnet);
375 
376 	return (error);
377 }
378 
379 int
380 mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf)
381 {
382 	struct label *label;
383 	int error;
384 
385 	M_ASSERTPKTHDR(mbuf);
386 
387 	if (!mac_enforce_network)
388 		return (0);
389 
390 	label = mac_mbuf_to_label(mbuf);
391 
392 	MAC_IFNET_LOCK(ifnet);
393 	MAC_CHECK(check_ifnet_transmit, ifnet, ifnet->if_label, mbuf,
394 	    label);
395 	MAC_IFNET_UNLOCK(ifnet);
396 
397 	return (error);
398 }
399 
400 int
401 mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr,
402     struct ifnet *ifnet)
403 {
404 	char *elements, *buffer;
405 	struct label *intlabel;
406 	struct mac mac;
407 	int error;
408 
409 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
410 	if (error)
411 		return (error);
412 
413 	error = mac_check_structmac_consistent(&mac);
414 	if (error)
415 		return (error);
416 
417 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
418 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
419 	if (error) {
420 		free(elements, M_MACTEMP);
421 		return (error);
422 	}
423 
424 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
425 	intlabel = mac_ifnet_label_alloc();
426 	MAC_IFNET_LOCK(ifnet);
427 	mac_copy_ifnet_label(ifnet->if_label, intlabel);
428 	MAC_IFNET_UNLOCK(ifnet);
429 	error = mac_externalize_ifnet_label(ifnet->if_label, elements,
430 	    buffer, mac.m_buflen);
431 	mac_ifnet_label_free(intlabel);
432 	if (error == 0)
433 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
434 
435 	free(buffer, M_MACTEMP);
436 	free(elements, M_MACTEMP);
437 
438 	return (error);
439 }
440 
441 int
442 mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr,
443     struct ifnet *ifnet)
444 {
445 	struct label *intlabel;
446 	struct mac mac;
447 	char *buffer;
448 	int error;
449 
450 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
451 	if (error)
452 		return (error);
453 
454 	error = mac_check_structmac_consistent(&mac);
455 	if (error)
456 		return (error);
457 
458 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
459 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
460 	if (error) {
461 		free(buffer, M_MACTEMP);
462 		return (error);
463 	}
464 
465 	intlabel = mac_ifnet_label_alloc();
466 	error = mac_internalize_ifnet_label(intlabel, buffer);
467 	free(buffer, M_MACTEMP);
468 	if (error) {
469 		mac_ifnet_label_free(intlabel);
470 		return (error);
471 	}
472 
473 	/*
474 	 * XXX: Note that this is a redundant privilege check, since policies
475 	 * impose this check themselves if required by the policy.
476 	 * Eventually, this should go away.
477 	 */
478 	error = priv_check_cred(cred, PRIV_NET_SETIFMAC, 0);
479 	if (error) {
480 		mac_ifnet_label_free(intlabel);
481 		return (error);
482 	}
483 
484 	MAC_IFNET_LOCK(ifnet);
485 	MAC_CHECK(check_ifnet_relabel, cred, ifnet, ifnet->if_label,
486 	    intlabel);
487 	if (error) {
488 		MAC_IFNET_UNLOCK(ifnet);
489 		mac_ifnet_label_free(intlabel);
490 		return (error);
491 	}
492 
493 	MAC_PERFORM(relabel_ifnet, cred, ifnet, ifnet->if_label, intlabel);
494 	MAC_IFNET_UNLOCK(ifnet);
495 
496 	mac_ifnet_label_free(intlabel);
497 	return (0);
498 }
499