xref: /freebsd/sys/security/mac/mac_net.c (revision 6ccbb635d7b228a34d0eb8bb16b767a233c21166)
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/sbuf.h>
49 #include <sys/systm.h>
50 #include <sys/mount.h>
51 #include <sys/file.h>
52 #include <sys/namei.h>
53 #include <sys/protosw.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <sys/sysctl.h>
57 
58 #include <sys/mac_policy.h>
59 
60 #include <net/bpfdesc.h>
61 #include <net/if.h>
62 #include <net/if_var.h>
63 
64 #include <security/mac/mac_internal.h>
65 
66 /*
67  * mac_enforce_network is used by IPv4 and IPv6 checks, and so must
68  * be non-static for now.
69  */
70 int	mac_enforce_network = 1;
71 SYSCTL_INT(_security_mac, OID_AUTO, enforce_network, CTLFLAG_RW,
72     &mac_enforce_network, 0, "Enforce MAC policy on network packets");
73 TUNABLE_INT("security.mac.enforce_network", &mac_enforce_network);
74 
75 #ifdef MAC_DEBUG
76 static unsigned int nmacbpfdescs, nmacifnets, nmacmbufs;
77 
78 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, bpfdescs, CTLFLAG_RD,
79     &nmacbpfdescs, 0, "number of bpfdescs in use");
80 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, ifnets, CTLFLAG_RD,
81     &nmacifnets, 0, "number of ifnets in use");
82 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, mbufs, CTLFLAG_RD,
83     &nmacmbufs, 0, "number of mbufs in use");
84 #endif
85 
86 struct label *
87 mac_mbuf_to_label(struct mbuf *mbuf)
88 {
89 	struct m_tag *tag;
90 	struct label *label;
91 
92 	tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL);
93 	label = (struct label *)(tag+1);
94 
95 	return (label);
96 }
97 
98 static struct label *
99 mac_bpfdesc_label_alloc(void)
100 {
101 	struct label *label;
102 
103 	label = mac_labelzone_alloc(M_WAITOK);
104 	MAC_PERFORM(init_bpfdesc_label, label);
105 	MAC_DEBUG_COUNTER_INC(&nmacbpfdescs);
106 	return (label);
107 }
108 
109 void
110 mac_init_bpfdesc(struct bpf_d *bpf_d)
111 {
112 
113 	bpf_d->bd_label = mac_bpfdesc_label_alloc();
114 }
115 
116 static struct label *
117 mac_ifnet_label_alloc(void)
118 {
119 	struct label *label;
120 
121 	label = mac_labelzone_alloc(M_WAITOK);
122 	MAC_PERFORM(init_ifnet_label, label);
123 	MAC_DEBUG_COUNTER_INC(&nmacifnets);
124 	return (label);
125 }
126 
127 void
128 mac_init_ifnet(struct ifnet *ifp)
129 {
130 
131 	ifp->if_label = mac_ifnet_label_alloc();
132 }
133 
134 int
135 mac_init_mbuf_tag(struct m_tag *tag, int flag)
136 {
137 	struct label *label;
138 	int error;
139 
140 	label = (struct label *) (tag + 1);
141 	mac_init_label(label);
142 
143 	MAC_CHECK(init_mbuf_label, label, flag);
144 	if (error) {
145 		MAC_PERFORM(destroy_mbuf_label, label);
146 		mac_destroy_label(label);
147 	} else {
148 		MAC_DEBUG_COUNTER_INC(&nmacmbufs);
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 	MAC_DEBUG_COUNTER_DEC(&nmacbpfdescs);
189 }
190 
191 void
192 mac_destroy_bpfdesc(struct bpf_d *bpf_d)
193 {
194 
195 	mac_bpfdesc_label_free(bpf_d->bd_label);
196 	bpf_d->bd_label = NULL;
197 }
198 
199 static void
200 mac_ifnet_label_free(struct label *label)
201 {
202 
203 	MAC_PERFORM(destroy_ifnet_label, label);
204 	mac_labelzone_free(label);
205 	MAC_DEBUG_COUNTER_DEC(&nmacifnets);
206 }
207 
208 void
209 mac_destroy_ifnet(struct ifnet *ifp)
210 {
211 
212 	mac_ifnet_label_free(ifp->if_label);
213 	ifp->if_label = NULL;
214 }
215 
216 void
217 mac_destroy_mbuf_tag(struct m_tag *tag)
218 {
219 	struct label *label;
220 
221 	label = (struct label *)(tag+1);
222 
223 	MAC_PERFORM(destroy_mbuf_label, label);
224 	mac_destroy_label(label);
225 	MAC_DEBUG_COUNTER_DEC(&nmacmbufs);
226 }
227 
228 void
229 mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest)
230 {
231 	struct label *src_label, *dest_label;
232 
233 	src_label = (struct label *)(src+1);
234 	dest_label = (struct label *)(dest+1);
235 
236 	/*
237 	 * mac_init_mbuf_tag() is called on the target tag in
238 	 * m_tag_copy(), so we don't need to call it here.
239 	 */
240 	MAC_PERFORM(copy_mbuf_label, src_label, dest_label);
241 }
242 
243 static int
244 mac_externalize_ifnet_label(struct label *label, char *elements,
245     char *outbuf, size_t outbuflen)
246 {
247 	int error;
248 
249 	MAC_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen);
250 
251 	return (error);
252 }
253 
254 static int
255 mac_internalize_ifnet_label(struct label *label, char *string)
256 {
257 	int error;
258 
259 	MAC_INTERNALIZE(ifnet, label, string);
260 
261 	return (error);
262 }
263 
264 void
265 mac_create_ifnet(struct ifnet *ifnet)
266 {
267 
268 	MAC_PERFORM(create_ifnet, ifnet, ifnet->if_label);
269 }
270 
271 void
272 mac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d)
273 {
274 
275 	MAC_PERFORM(create_bpfdesc, cred, bpf_d, bpf_d->bd_label);
276 }
277 
278 void
279 mac_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct mbuf *newmbuf)
280 {
281 	struct label *oldmbuflabel, *newmbuflabel;
282 
283 	oldmbuflabel = mac_mbuf_to_label(oldmbuf);
284 	newmbuflabel = mac_mbuf_to_label(newmbuf);
285 
286 	MAC_PERFORM(create_mbuf_from_mbuf, oldmbuf, oldmbuflabel, newmbuf,
287 	    newmbuflabel);
288 }
289 
290 void
291 mac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct mbuf *mbuf)
292 {
293 	struct label *label;
294 
295 	BPFD_LOCK_ASSERT(bpf_d);
296 
297 	label = mac_mbuf_to_label(mbuf);
298 
299 	MAC_PERFORM(create_mbuf_from_bpfdesc, bpf_d, bpf_d->bd_label, mbuf,
300 	    label);
301 }
302 
303 void
304 mac_create_mbuf_linklayer(struct ifnet *ifnet, struct mbuf *mbuf)
305 {
306 	struct label *label;
307 
308 	label = mac_mbuf_to_label(mbuf);
309 
310 	MAC_PERFORM(create_mbuf_linklayer, ifnet, ifnet->if_label, mbuf,
311 	    label);
312 }
313 
314 void
315 mac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct mbuf *mbuf)
316 {
317 	struct label *label;
318 
319 	label = mac_mbuf_to_label(mbuf);
320 
321 	MAC_PERFORM(create_mbuf_from_ifnet, ifnet, ifnet->if_label, mbuf,
322 	    label);
323 }
324 
325 void
326 mac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct ifnet *ifnet,
327     struct mbuf *newmbuf)
328 {
329 	struct label *oldmbuflabel, *newmbuflabel;
330 
331 	oldmbuflabel = mac_mbuf_to_label(oldmbuf);
332 	newmbuflabel = mac_mbuf_to_label(newmbuf);
333 
334 	MAC_PERFORM(create_mbuf_multicast_encap, oldmbuf, oldmbuflabel,
335 	    ifnet, ifnet->if_label, newmbuf, newmbuflabel);
336 }
337 
338 void
339 mac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct mbuf *newmbuf)
340 {
341 	struct label *oldmbuflabel, *newmbuflabel;
342 
343 	oldmbuflabel = mac_mbuf_to_label(oldmbuf);
344 	newmbuflabel = mac_mbuf_to_label(newmbuf);
345 
346 	MAC_PERFORM(create_mbuf_netlayer, oldmbuf, oldmbuflabel, newmbuf,
347 	    newmbuflabel);
348 }
349 
350 int
351 mac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct ifnet *ifnet)
352 {
353 	int error;
354 
355 	BPFD_LOCK_ASSERT(bpf_d);
356 
357 	if (!mac_enforce_network)
358 		return (0);
359 
360 	MAC_CHECK(check_bpfdesc_receive, bpf_d, bpf_d->bd_label, ifnet,
361 	    ifnet->if_label);
362 
363 	return (error);
364 }
365 
366 int
367 mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf)
368 {
369 	struct label *label;
370 	int error;
371 
372 	M_ASSERTPKTHDR(mbuf);
373 
374 	if (!mac_enforce_network)
375 		return (0);
376 
377 	label = mac_mbuf_to_label(mbuf);
378 
379 	MAC_CHECK(check_ifnet_transmit, ifnet, ifnet->if_label, mbuf,
380 	    label);
381 
382 	return (error);
383 }
384 
385 int
386 mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr,
387     struct ifnet *ifnet)
388 {
389 	char *elements, *buffer;
390 	struct mac mac;
391 	int error;
392 
393 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
394 	if (error)
395 		return (error);
396 
397 	error = mac_check_structmac_consistent(&mac);
398 	if (error)
399 		return (error);
400 
401 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
402 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
403 	if (error) {
404 		free(elements, M_MACTEMP);
405 		return (error);
406 	}
407 
408 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
409 	error = mac_externalize_ifnet_label(ifnet->if_label, elements,
410 	    buffer, mac.m_buflen);
411 	if (error == 0)
412 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
413 
414 	free(buffer, M_MACTEMP);
415 	free(elements, M_MACTEMP);
416 
417 	return (error);
418 }
419 
420 int
421 mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr,
422     struct ifnet *ifnet)
423 {
424 	struct label *intlabel;
425 	struct mac mac;
426 	char *buffer;
427 	int error;
428 
429 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
430 	if (error)
431 		return (error);
432 
433 	error = mac_check_structmac_consistent(&mac);
434 	if (error)
435 		return (error);
436 
437 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
438 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
439 	if (error) {
440 		free(buffer, M_MACTEMP);
441 		return (error);
442 	}
443 
444 	intlabel = mac_ifnet_label_alloc();
445 	error = mac_internalize_ifnet_label(intlabel, buffer);
446 	free(buffer, M_MACTEMP);
447 	if (error) {
448 		mac_ifnet_label_free(intlabel);
449 		return (error);
450 	}
451 
452 	/*
453 	 * XXX: Note that this is a redundant privilege check, since
454 	 * policies impose this check themselves if required by the
455 	 * policy.  Eventually, this should go away.
456 	 */
457 	error = suser_cred(cred, 0);
458 	if (error) {
459 		mac_ifnet_label_free(intlabel);
460 		return (error);
461 	}
462 
463 	MAC_CHECK(check_ifnet_relabel, cred, ifnet, ifnet->if_label,
464 	    intlabel);
465 	if (error) {
466 		mac_ifnet_label_free(intlabel);
467 		return (error);
468 	}
469 
470 	MAC_PERFORM(relabel_ifnet, cred, ifnet, ifnet->if_label, intlabel);
471 
472 	mac_ifnet_label_free(intlabel);
473 	return (0);
474 }
475