xref: /freebsd/sys/security/mac/mac_net.c (revision 6607310b740c499e273ae5bbf1f308ed91b61c05)
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  * Copyright (c) 2006 SPARTA, Inc.
6  * All rights reserved.
7  *
8  * This software was developed by Robert Watson and Ilmar Habibulin for the
9  * TrustedBSD Project.
10  *
11  * This software was enhanced by SPARTA ISSO under SPAWAR contract
12  * N66001-04-C-6019 ("SEFOS").
13  *
14  * This software was developed for the FreeBSD Project in part by Network
15  * Associates Laboratories, the Security Research Division of Network
16  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
17  * as part of the DARPA CHATS research program.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  */
40 
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43 
44 #include "opt_mac.h"
45 
46 #include <sys/param.h>
47 #include <sys/kernel.h>
48 #include <sys/lock.h>
49 #include <sys/malloc.h>
50 #include <sys/mutex.h>
51 #include <sys/mac.h>
52 #include <sys/priv.h>
53 #include <sys/sbuf.h>
54 #include <sys/systm.h>
55 #include <sys/mount.h>
56 #include <sys/file.h>
57 #include <sys/namei.h>
58 #include <sys/protosw.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/sysctl.h>
62 
63 #include <net/bpfdesc.h>
64 #include <net/if.h>
65 #include <net/if_var.h>
66 
67 #include <security/mac/mac_framework.h>
68 #include <security/mac/mac_internal.h>
69 #include <security/mac/mac_policy.h>
70 
71 /*
72  * XXXRW: struct ifnet locking is incomplete in the network code, so we use
73  * our own global mutex for struct ifnet.  Non-ideal, but should help in the
74  * SMP environment.
75  */
76 struct mtx mac_ifnet_mtx;
77 MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF);
78 
79 /*
80  * Retrieve the label associated with an mbuf by searching for the tag.
81  * Depending on the value of mac_labelmbufs, it's possible that a label will
82  * not be present, in which case NULL is returned.  Policies must handle the
83  * possibility of an mbuf not having label storage if they do not enforce
84  * early loading.
85  */
86 struct label *
87 mac_mbuf_to_label(struct mbuf *m)
88 {
89 	struct m_tag *tag;
90 	struct label *label;
91 
92 	if (m == NULL)
93 		return (NULL);
94 	tag = m_tag_find(m, PACKET_TAG_MACLABEL, NULL);
95 	if (tag == NULL)
96 		return (NULL);
97 	label = (struct label *)(tag+1);
98 	return (label);
99 }
100 
101 static struct label *
102 mac_bpfdesc_label_alloc(void)
103 {
104 	struct label *label;
105 
106 	label = mac_labelzone_alloc(M_WAITOK);
107 	MAC_PERFORM(bpfdesc_init_label, label);
108 	return (label);
109 }
110 
111 void
112 mac_bpfdesc_init(struct bpf_d *d)
113 {
114 
115 	d->bd_label = mac_bpfdesc_label_alloc();
116 }
117 
118 static struct label *
119 mac_ifnet_label_alloc(void)
120 {
121 	struct label *label;
122 
123 	label = mac_labelzone_alloc(M_WAITOK);
124 	MAC_PERFORM(ifnet_init_label, label);
125 	return (label);
126 }
127 
128 void
129 mac_ifnet_init(struct ifnet *ifp)
130 {
131 
132 	ifp->if_label = mac_ifnet_label_alloc();
133 }
134 
135 int
136 mac_mbuf_tag_init(struct m_tag *tag, int flag)
137 {
138 	struct label *label;
139 	int error;
140 
141 	label = (struct label *) (tag + 1);
142 	mac_init_label(label);
143 
144 	MAC_CHECK(mbuf_init_label, label, flag);
145 	if (error) {
146 		MAC_PERFORM(mbuf_destroy_label, label);
147 		mac_destroy_label(label);
148 	}
149 	return (error);
150 }
151 
152 int
153 mac_mbuf_init(struct mbuf *m, int flag)
154 {
155 	struct m_tag *tag;
156 	int error;
157 
158 	M_ASSERTPKTHDR(m);
159 
160 #ifndef MAC_ALWAYS_LABEL_MBUF
161 	/*
162 	 * If conditionally allocating mbuf labels, don't allocate unless
163 	 * they are required.
164 	 */
165 	if (!mac_labelmbufs)
166 		return (0);
167 #endif
168 	tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label),
169 	    flag);
170 	if (tag == NULL)
171 		return (ENOMEM);
172 	error = mac_mbuf_tag_init(tag, flag);
173 	if (error) {
174 		m_tag_free(tag);
175 		return (error);
176 	}
177 	m_tag_prepend(m, tag);
178 	return (0);
179 }
180 
181 static void
182 mac_bpfdesc_label_free(struct label *label)
183 {
184 
185 	MAC_PERFORM(bpfdesc_destroy_label, label);
186 	mac_labelzone_free(label);
187 }
188 
189 void
190 mac_bpfdesc_destroy(struct bpf_d *d)
191 {
192 
193 	mac_bpfdesc_label_free(d->bd_label);
194 	d->bd_label = NULL;
195 }
196 
197 static void
198 mac_ifnet_label_free(struct label *label)
199 {
200 
201 	MAC_PERFORM(ifnet_destroy_label, label);
202 	mac_labelzone_free(label);
203 }
204 
205 void
206 mac_ifnet_destroy(struct ifnet *ifp)
207 {
208 
209 	mac_ifnet_label_free(ifp->if_label);
210 	ifp->if_label = NULL;
211 }
212 
213 void
214 mac_mbuf_tag_destroy(struct m_tag *tag)
215 {
216 	struct label *label;
217 
218 	label = (struct label *)(tag+1);
219 
220 	MAC_PERFORM(mbuf_destroy_label, label);
221 	mac_destroy_label(label);
222 }
223 
224 /*
225  * mac_mbuf_tag_copy is called when an mbuf header is duplicated, in which
226  * case the labels must also be duplicated.
227  */
228 void
229 mac_mbuf_tag_copy(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_mbuf_tag_init() is called on the target tag in m_tag_copy(),
238 	 * so we don't need to call it here.
239 	 */
240 	MAC_PERFORM(mbuf_copy_label, src_label, dest_label);
241 }
242 
243 void
244 mac_mbuf_copy(struct mbuf *m_from, struct mbuf *m_to)
245 {
246 	struct label *src_label, *dest_label;
247 
248 	src_label = mac_mbuf_to_label(m_from);
249 	dest_label = mac_mbuf_to_label(m_to);
250 
251 	MAC_PERFORM(mbuf_copy_label, src_label, dest_label);
252 }
253 
254 static void
255 mac_ifnet_copy_label(struct label *src, struct label *dest)
256 {
257 
258 	MAC_PERFORM(ifnet_copy_label, src, dest);
259 }
260 
261 static int
262 mac_ifnet_externalize_label(struct label *label, char *elements,
263     char *outbuf, size_t outbuflen)
264 {
265 	int error;
266 
267 	MAC_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen);
268 
269 	return (error);
270 }
271 
272 static int
273 mac_ifnet_internalize_label(struct label *label, char *string)
274 {
275 	int error;
276 
277 	MAC_INTERNALIZE(ifnet, label, string);
278 
279 	return (error);
280 }
281 
282 void
283 mac_ifnet_create(struct ifnet *ifp)
284 {
285 
286 	MAC_IFNET_LOCK(ifp);
287 	MAC_PERFORM(ifnet_create, ifp, ifp->if_label);
288 	MAC_IFNET_UNLOCK(ifp);
289 }
290 
291 void
292 mac_bpfdesc_create(struct ucred *cred, struct bpf_d *d)
293 {
294 
295 	MAC_PERFORM(bpfdesc_create, cred, d, d->bd_label);
296 }
297 
298 void
299 mac_bpfdesc_create_mbuf(struct bpf_d *d, struct mbuf *m)
300 {
301 	struct label *label;
302 
303 	BPFD_LOCK_ASSERT(d);
304 
305 	label = mac_mbuf_to_label(m);
306 
307 	MAC_PERFORM(bpfdesc_create_mbuf, d, d->bd_label, m, label);
308 }
309 
310 void
311 mac_ifnet_create_mbuf(struct ifnet *ifp, struct mbuf *m)
312 {
313 	struct label *label;
314 
315 	label = mac_mbuf_to_label(m);
316 
317 	MAC_IFNET_LOCK(ifp);
318 	MAC_PERFORM(ifnet_create_mbuf, ifp, ifp->if_label, m, label);
319 	MAC_IFNET_UNLOCK(ifp);
320 }
321 
322 int
323 mac_bpfdesc_check_receive(struct bpf_d *d, struct ifnet *ifp)
324 {
325 	int error;
326 
327 	BPFD_LOCK_ASSERT(d);
328 
329 	MAC_IFNET_LOCK(ifp);
330 	MAC_CHECK(bpfdesc_check_receive, d, d->bd_label, ifp, ifp->if_label);
331 	MAC_IFNET_UNLOCK(ifp);
332 
333 	return (error);
334 }
335 
336 int
337 mac_ifnet_check_transmit(struct ifnet *ifp, struct mbuf *m)
338 {
339 	struct label *label;
340 	int error;
341 
342 	M_ASSERTPKTHDR(m);
343 
344 	label = mac_mbuf_to_label(m);
345 
346 	MAC_IFNET_LOCK(ifp);
347 	MAC_CHECK(ifnet_check_transmit, ifp, ifp->if_label, m, label);
348 	MAC_IFNET_UNLOCK(ifp);
349 
350 	return (error);
351 }
352 
353 int
354 mac_ifnet_ioctl_get(struct ucred *cred, struct ifreq *ifr,
355     struct ifnet *ifp)
356 {
357 	char *elements, *buffer;
358 	struct label *intlabel;
359 	struct mac mac;
360 	int error;
361 
362 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
363 	if (error)
364 		return (error);
365 
366 	error = mac_check_structmac_consistent(&mac);
367 	if (error)
368 		return (error);
369 
370 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
371 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
372 	if (error) {
373 		free(elements, M_MACTEMP);
374 		return (error);
375 	}
376 
377 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
378 	intlabel = mac_ifnet_label_alloc();
379 	MAC_IFNET_LOCK(ifp);
380 	mac_ifnet_copy_label(ifp->if_label, intlabel);
381 	MAC_IFNET_UNLOCK(ifp);
382 	error = mac_ifnet_externalize_label(intlabel, elements, buffer,
383 	    mac.m_buflen);
384 	mac_ifnet_label_free(intlabel);
385 	if (error == 0)
386 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
387 
388 	free(buffer, M_MACTEMP);
389 	free(elements, M_MACTEMP);
390 
391 	return (error);
392 }
393 
394 int
395 mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp)
396 {
397 	struct label *intlabel;
398 	struct mac mac;
399 	char *buffer;
400 	int error;
401 
402 	error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
403 	if (error)
404 		return (error);
405 
406 	error = mac_check_structmac_consistent(&mac);
407 	if (error)
408 		return (error);
409 
410 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
411 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
412 	if (error) {
413 		free(buffer, M_MACTEMP);
414 		return (error);
415 	}
416 
417 	intlabel = mac_ifnet_label_alloc();
418 	error = mac_ifnet_internalize_label(intlabel, buffer);
419 	free(buffer, M_MACTEMP);
420 	if (error) {
421 		mac_ifnet_label_free(intlabel);
422 		return (error);
423 	}
424 
425 	/*
426 	 * XXX: Note that this is a redundant privilege check, since policies
427 	 * impose this check themselves if required by the policy
428 	 * Eventually, this should go away.
429 	 */
430 	error = priv_check_cred(cred, PRIV_NET_SETIFMAC, 0);
431 	if (error) {
432 		mac_ifnet_label_free(intlabel);
433 		return (error);
434 	}
435 
436 	MAC_IFNET_LOCK(ifp);
437 	MAC_CHECK(ifnet_check_relabel, cred, ifp, ifp->if_label, intlabel);
438 	if (error) {
439 		MAC_IFNET_UNLOCK(ifp);
440 		mac_ifnet_label_free(intlabel);
441 		return (error);
442 	}
443 
444 	MAC_PERFORM(ifnet_relabel, cred, ifp, ifp->if_label, intlabel);
445 	MAC_IFNET_UNLOCK(ifp);
446 
447 	mac_ifnet_label_free(intlabel);
448 	return (0);
449 }
450