xref: /freebsd/sys/security/mac/mac_inet.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 /*-
2  * Copyright (c) 1999-2002, 2007, 2009, 2019 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  * Copyright (c) 2008 Apple Inc.
7  * All rights reserved.
8  *
9  * This software was developed by Robert Watson and Ilmar Habibulin for the
10  * TrustedBSD Project.
11  *
12  * This software was developed for the FreeBSD Project in part by Network
13  * Associates Laboratories, the Security Research Division of Network
14  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15  * as part of the DARPA CHATS research program.
16  *
17  * This software was enhanced by SPARTA ISSO under SPAWAR contract
18  * N66001-04-C-6019 ("SEFOS").
19  *
20  * This software was developed at the University of Cambridge Computer
21  * Laboratory with support from a grant from Google, Inc.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  */
44 
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47 
48 #include "opt_mac.h"
49 
50 #include <sys/param.h>
51 #include <sys/kernel.h>
52 #include <sys/lock.h>
53 #include <sys/malloc.h>
54 #include <sys/mutex.h>
55 #include <sys/sbuf.h>
56 #include <sys/sdt.h>
57 #include <sys/systm.h>
58 #include <sys/mount.h>
59 #include <sys/file.h>
60 #include <sys/namei.h>
61 #include <sys/protosw.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/sysctl.h>
65 
66 #include <net/if.h>
67 #include <net/if_var.h>
68 
69 #include <netinet/in.h>
70 #include <netinet/in_pcb.h>
71 #include <netinet/ip_var.h>
72 
73 #include <security/mac/mac_framework.h>
74 #include <security/mac/mac_internal.h>
75 #include <security/mac/mac_policy.h>
76 
77 static struct label *
78 mac_inpcb_label_alloc(int flag)
79 {
80 	struct label *label;
81 	int error;
82 
83 	label = mac_labelzone_alloc(flag);
84 	if (label == NULL)
85 		return (NULL);
86 	if (flag & M_WAITOK)
87 		MAC_POLICY_CHECK(inpcb_init_label, label, flag);
88 	else
89 		MAC_POLICY_CHECK_NOSLEEP(inpcb_init_label, label, flag);
90 	if (error) {
91 		MAC_POLICY_PERFORM_NOSLEEP(inpcb_destroy_label, label);
92 		mac_labelzone_free(label);
93 		return (NULL);
94 	}
95 	return (label);
96 }
97 
98 int
99 mac_inpcb_init(struct inpcb *inp, int flag)
100 {
101 
102 	if (mac_labeled & MPC_OBJECT_INPCB) {
103 		inp->inp_label = mac_inpcb_label_alloc(flag);
104 		if (inp->inp_label == NULL)
105 			return (ENOMEM);
106 	} else
107 		inp->inp_label = NULL;
108 	return (0);
109 }
110 
111 /* Check with rules in module if the IPv4 address is allowed. */
112 int
113 mac_inet_check_add_addr(struct ucred *cred, const struct in_addr *ia,
114     struct ifnet *ifp)
115 {
116 	int error;
117 
118 	MAC_POLICY_CHECK(ip4_check_jail, cred, ia, ifp);
119 	return (error);
120 }
121 
122 static struct label *
123 mac_ipq_label_alloc(int flag)
124 {
125 	struct label *label;
126 	int error;
127 
128 	label = mac_labelzone_alloc(flag);
129 	if (label == NULL)
130 		return (NULL);
131 
132 	if (flag & M_WAITOK)
133 		MAC_POLICY_CHECK(ipq_init_label, label, flag);
134 	else
135 		MAC_POLICY_CHECK_NOSLEEP(ipq_init_label, label, flag);
136 	if (error) {
137 		MAC_POLICY_PERFORM_NOSLEEP(ipq_destroy_label, label);
138 		mac_labelzone_free(label);
139 		return (NULL);
140 	}
141 	return (label);
142 }
143 
144 int
145 mac_ipq_init(struct ipq *q, int flag)
146 {
147 
148 	if (mac_labeled & MPC_OBJECT_IPQ) {
149 		q->ipq_label = mac_ipq_label_alloc(flag);
150 		if (q->ipq_label == NULL)
151 			return (ENOMEM);
152 	} else
153 		q->ipq_label = NULL;
154 	return (0);
155 }
156 
157 static void
158 mac_inpcb_label_free(struct label *label)
159 {
160 
161 	MAC_POLICY_PERFORM_NOSLEEP(inpcb_destroy_label, label);
162 	mac_labelzone_free(label);
163 }
164 
165 void
166 mac_inpcb_destroy(struct inpcb *inp)
167 {
168 
169 	if (inp->inp_label != NULL) {
170 		mac_inpcb_label_free(inp->inp_label);
171 		inp->inp_label = NULL;
172 	}
173 }
174 
175 static void
176 mac_ipq_label_free(struct label *label)
177 {
178 
179 	MAC_POLICY_PERFORM_NOSLEEP(ipq_destroy_label, label);
180 	mac_labelzone_free(label);
181 }
182 
183 void
184 mac_ipq_destroy(struct ipq *q)
185 {
186 
187 	if (q->ipq_label != NULL) {
188 		mac_ipq_label_free(q->ipq_label);
189 		q->ipq_label = NULL;
190 	}
191 }
192 
193 void
194 mac_inpcb_create(struct socket *so, struct inpcb *inp)
195 {
196 
197 	MAC_POLICY_PERFORM_NOSLEEP(inpcb_create, so, so->so_label, inp,
198 	    inp->inp_label);
199 }
200 
201 void
202 mac_ipq_reassemble(struct ipq *q, struct mbuf *m)
203 {
204 	struct label *label;
205 
206 	if (mac_policy_count == 0)
207 		return;
208 
209 	label = mac_mbuf_to_label(m);
210 
211 	MAC_POLICY_PERFORM_NOSLEEP(ipq_reassemble, q, q->ipq_label, m,
212 	    label);
213 }
214 
215 void
216 mac_netinet_fragment(struct mbuf *m, struct mbuf *frag)
217 {
218 	struct label *mlabel, *fraglabel;
219 
220 	if (mac_policy_count == 0)
221 		return;
222 
223 	mlabel = mac_mbuf_to_label(m);
224 	fraglabel = mac_mbuf_to_label(frag);
225 
226 	MAC_POLICY_PERFORM_NOSLEEP(netinet_fragment, m, mlabel, frag,
227 	    fraglabel);
228 }
229 
230 void
231 mac_ipq_create(struct mbuf *m, struct ipq *q)
232 {
233 	struct label *label;
234 
235 	if (mac_policy_count == 0)
236 		return;
237 
238 	label = mac_mbuf_to_label(m);
239 
240 	MAC_POLICY_PERFORM_NOSLEEP(ipq_create, m, label, q, q->ipq_label);
241 }
242 
243 void
244 mac_inpcb_create_mbuf(struct inpcb *inp, struct mbuf *m)
245 {
246 	struct label *mlabel;
247 
248 	INP_LOCK_ASSERT(inp);
249 
250 	if (mac_policy_count == 0)
251 		return;
252 
253 	mlabel = mac_mbuf_to_label(m);
254 
255 	MAC_POLICY_PERFORM_NOSLEEP(inpcb_create_mbuf, inp, inp->inp_label, m,
256 	    mlabel);
257 }
258 
259 int
260 mac_ipq_match(struct mbuf *m, struct ipq *q)
261 {
262 	struct label *label;
263 	int result;
264 
265 	if (mac_policy_count == 0)
266 		return (1);
267 
268 	label = mac_mbuf_to_label(m);
269 
270 	result = 1;
271 	MAC_POLICY_BOOLEAN_NOSLEEP(ipq_match, &&, m, label, q, q->ipq_label);
272 
273 	return (result);
274 }
275 
276 void
277 mac_netinet_arp_send(struct ifnet *ifp, struct mbuf *m)
278 {
279 	struct label *mlabel;
280 	int locked;
281 
282 	if (mac_policy_count == 0)
283 		return;
284 
285 	mlabel = mac_mbuf_to_label(m);
286 
287 	MAC_IFNET_LOCK(ifp, locked);
288 	MAC_POLICY_PERFORM_NOSLEEP(netinet_arp_send, ifp, if_getmaclabel(ifp),
289 	    m, mlabel);
290 	MAC_IFNET_UNLOCK(ifp, locked);
291 }
292 
293 void
294 mac_netinet_icmp_reply(struct mbuf *mrecv, struct mbuf *msend)
295 {
296 	struct label *mrecvlabel, *msendlabel;
297 
298 	if (mac_policy_count == 0)
299 		return;
300 
301 	mrecvlabel = mac_mbuf_to_label(mrecv);
302 	msendlabel = mac_mbuf_to_label(msend);
303 
304 	MAC_POLICY_PERFORM_NOSLEEP(netinet_icmp_reply, mrecv, mrecvlabel,
305 	    msend, msendlabel);
306 }
307 
308 void
309 mac_netinet_icmp_replyinplace(struct mbuf *m)
310 {
311 	struct label *label;
312 
313 	if (mac_policy_count == 0)
314 		return;
315 
316 	label = mac_mbuf_to_label(m);
317 
318 	MAC_POLICY_PERFORM_NOSLEEP(netinet_icmp_replyinplace, m, label);
319 }
320 
321 void
322 mac_netinet_igmp_send(struct ifnet *ifp, struct mbuf *m)
323 {
324 	struct label *mlabel;
325 	int locked;
326 
327 	if (mac_policy_count == 0)
328 		return;
329 
330 	mlabel = mac_mbuf_to_label(m);
331 
332 	MAC_IFNET_LOCK(ifp, locked);
333 	MAC_POLICY_PERFORM_NOSLEEP(netinet_igmp_send, ifp, if_getmaclabel(ifp),
334 	    m, mlabel);
335 	MAC_IFNET_UNLOCK(ifp, locked);
336 }
337 
338 void
339 mac_netinet_tcp_reply(struct mbuf *m)
340 {
341 	struct label *label;
342 
343 	if (mac_policy_count == 0)
344 		return;
345 
346 	label = mac_mbuf_to_label(m);
347 
348 	MAC_POLICY_PERFORM_NOSLEEP(netinet_tcp_reply, m, label);
349 }
350 
351 void
352 mac_ipq_update(struct mbuf *m, struct ipq *q)
353 {
354 	struct label *label;
355 
356 	if (mac_policy_count == 0)
357 		return;
358 
359 	label = mac_mbuf_to_label(m);
360 
361 	MAC_POLICY_PERFORM_NOSLEEP(ipq_update, m, label, q, q->ipq_label);
362 }
363 
364 MAC_CHECK_PROBE_DEFINE2(inpcb_check_deliver, "struct inpcb *",
365     "struct mbuf *");
366 
367 int
368 mac_inpcb_check_deliver(struct inpcb *inp, struct mbuf *m)
369 {
370 	struct label *label;
371 	int error;
372 
373 	M_ASSERTPKTHDR(m);
374 
375 	if (mac_policy_count == 0)
376 		return (0);
377 
378 	label = mac_mbuf_to_label(m);
379 
380 	MAC_POLICY_CHECK_NOSLEEP(inpcb_check_deliver, inp, inp->inp_label, m,
381 	    label);
382 	MAC_CHECK_PROBE2(inpcb_check_deliver, error, inp, m);
383 
384 	return (error);
385 }
386 
387 MAC_CHECK_PROBE_DEFINE2(inpcb_check_visible, "struct ucred *",
388     "struct inpcb *");
389 
390 int
391 mac_inpcb_check_visible(struct ucred *cred, struct inpcb *inp)
392 {
393 	int error;
394 
395 	INP_LOCK_ASSERT(inp);
396 
397 	MAC_POLICY_CHECK_NOSLEEP(inpcb_check_visible, cred, inp,
398 	    inp->inp_label);
399 	MAC_CHECK_PROBE2(inpcb_check_visible, error, cred, inp);
400 
401 	return (error);
402 }
403 
404 void
405 mac_inpcb_sosetlabel(struct socket *so, struct inpcb *inp)
406 {
407 
408 	INP_WLOCK_ASSERT(inp);
409 	SOCK_LOCK_ASSERT(so);
410 
411 	MAC_POLICY_PERFORM_NOSLEEP(inpcb_sosetlabel, so, so->so_label, inp,
412 	    inp->inp_label);
413 }
414 
415 void
416 mac_netinet_firewall_reply(struct mbuf *mrecv, struct mbuf *msend)
417 {
418 	struct label *mrecvlabel, *msendlabel;
419 
420 	M_ASSERTPKTHDR(mrecv);
421 	M_ASSERTPKTHDR(msend);
422 
423 	if (mac_policy_count == 0)
424 		return;
425 
426 	mrecvlabel = mac_mbuf_to_label(mrecv);
427 	msendlabel = mac_mbuf_to_label(msend);
428 
429 	MAC_POLICY_PERFORM_NOSLEEP(netinet_firewall_reply, mrecv, mrecvlabel,
430 	    msend, msendlabel);
431 }
432 
433 void
434 mac_netinet_firewall_send(struct mbuf *m)
435 {
436 	struct label *label;
437 
438 	M_ASSERTPKTHDR(m);
439 
440 	if (mac_policy_count == 0)
441 		return;
442 
443 	label = mac_mbuf_to_label(m);
444 
445 	MAC_POLICY_PERFORM_NOSLEEP(netinet_firewall_send, m, label);
446 }
447 
448 /*
449  * These functions really should be referencing the syncache structure
450  * instead of the label.  However, due to some of the complexities associated
451  * with exposing this syncache structure we operate directly on its label
452  * pointer.  This should be OK since we aren't making any access control
453  * decisions within this code directly, we are merely allocating and copying
454  * label storage so we can properly initialize mbuf labels for any packets
455  * the syncache code might create.
456  */
457 void
458 mac_syncache_destroy(struct label **label)
459 {
460 
461 	if (*label != NULL) {
462 		MAC_POLICY_PERFORM_NOSLEEP(syncache_destroy_label, *label);
463 		mac_labelzone_free(*label);
464 		*label = NULL;
465 	}
466 }
467 
468 int
469 mac_syncache_init(struct label **label)
470 {
471 	int error;
472 
473 	if (mac_labeled & MPC_OBJECT_SYNCACHE) {
474 		*label = mac_labelzone_alloc(M_NOWAIT);
475 		if (*label == NULL)
476 			return (ENOMEM);
477 		/*
478 		 * Since we are holding the inpcb locks the policy can not
479 		 * allocate policy specific label storage using M_WAITOK.  So
480 		 * we need to do a MAC_CHECK instead of the typical
481 		 * MAC_PERFORM so we can propagate allocation failures back
482 		 * to the syncache code.
483 		 */
484 		MAC_POLICY_CHECK_NOSLEEP(syncache_init_label, *label,
485 		    M_NOWAIT);
486 		if (error) {
487 			MAC_POLICY_PERFORM_NOSLEEP(syncache_destroy_label,
488 			    *label);
489 			mac_labelzone_free(*label);
490 		}
491 		return (error);
492 	} else
493 		*label = NULL;
494 	return (0);
495 }
496 
497 void
498 mac_syncache_create(struct label *label, struct inpcb *inp)
499 {
500 
501 	INP_LOCK_ASSERT(inp);
502 
503 	MAC_POLICY_PERFORM_NOSLEEP(syncache_create, label, inp);
504 }
505 
506 void
507 mac_syncache_create_mbuf(struct label *sc_label, struct mbuf *m)
508 {
509 	struct label *mlabel;
510 
511 	M_ASSERTPKTHDR(m);
512 
513 	if (mac_policy_count == 0)
514 		return;
515 
516 	mlabel = mac_mbuf_to_label(m);
517 
518 	MAC_POLICY_PERFORM_NOSLEEP(syncache_create_mbuf, sc_label, m,
519 	    mlabel);
520 }
521