xref: /freebsd/sys/security/mac/mac_inet.c (revision b3aaa0cc21c63d388230c7ef2a80abd631ff20d5)
1 /*-
2  * Copyright (c) 1999-2002, 2007 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  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  */
41 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include "opt_mac.h"
46 
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/lock.h>
50 #include <sys/malloc.h>
51 #include <sys/mutex.h>
52 #include <sys/sbuf.h>
53 #include <sys/systm.h>
54 #include <sys/mount.h>
55 #include <sys/file.h>
56 #include <sys/namei.h>
57 #include <sys/protosw.h>
58 #include <sys/socket.h>
59 #include <sys/socketvar.h>
60 #include <sys/sysctl.h>
61 
62 #include <net/if.h>
63 #include <net/if_var.h>
64 
65 #include <netinet/in.h>
66 #include <netinet/in_pcb.h>
67 #include <netinet/ip_var.h>
68 
69 #include <security/mac/mac_framework.h>
70 #include <security/mac/mac_internal.h>
71 #include <security/mac/mac_policy.h>
72 
73 static struct label *
74 mac_inpcb_label_alloc(int flag)
75 {
76 	struct label *label;
77 	int error;
78 
79 	label = mac_labelzone_alloc(flag);
80 	if (label == NULL)
81 		return (NULL);
82 	MAC_CHECK(inpcb_init_label, label, flag);
83 	if (error) {
84 		MAC_PERFORM(inpcb_destroy_label, label);
85 		mac_labelzone_free(label);
86 		return (NULL);
87 	}
88 	return (label);
89 }
90 
91 int
92 mac_inpcb_init(struct inpcb *inp, int flag)
93 {
94 
95 	if (mac_labeled & MPC_OBJECT_INPCB) {
96 		inp->inp_label = mac_inpcb_label_alloc(flag);
97 		if (inp->inp_label == NULL)
98 			return (ENOMEM);
99 	} else
100 		inp->inp_label = NULL;
101 	return (0);
102 }
103 
104 static struct label *
105 mac_ipq_label_alloc(int flag)
106 {
107 	struct label *label;
108 	int error;
109 
110 	label = mac_labelzone_alloc(flag);
111 	if (label == NULL)
112 		return (NULL);
113 
114 	MAC_CHECK(ipq_init_label, label, flag);
115 	if (error) {
116 		MAC_PERFORM(ipq_destroy_label, label);
117 		mac_labelzone_free(label);
118 		return (NULL);
119 	}
120 	return (label);
121 }
122 
123 int
124 mac_ipq_init(struct ipq *q, int flag)
125 {
126 
127 	if (mac_labeled & MPC_OBJECT_IPQ) {
128 		q->ipq_label = mac_ipq_label_alloc(flag);
129 		if (q->ipq_label == NULL)
130 			return (ENOMEM);
131 	} else
132 		q->ipq_label = NULL;
133 	return (0);
134 }
135 
136 static void
137 mac_inpcb_label_free(struct label *label)
138 {
139 
140 	MAC_PERFORM(inpcb_destroy_label, label);
141 	mac_labelzone_free(label);
142 }
143 
144 void
145 mac_inpcb_destroy(struct inpcb *inp)
146 {
147 
148 	if (inp->inp_label != NULL) {
149 		mac_inpcb_label_free(inp->inp_label);
150 		inp->inp_label = NULL;
151 	}
152 }
153 
154 static void
155 mac_ipq_label_free(struct label *label)
156 {
157 
158 	MAC_PERFORM(ipq_destroy_label, label);
159 	mac_labelzone_free(label);
160 }
161 
162 void
163 mac_ipq_destroy(struct ipq *q)
164 {
165 
166 	if (q->ipq_label != NULL) {
167 		mac_ipq_label_free(q->ipq_label);
168 		q->ipq_label = NULL;
169 	}
170 }
171 
172 void
173 mac_inpcb_create(struct socket *so, struct inpcb *inp)
174 {
175 
176 	MAC_PERFORM(inpcb_create, so, so->so_label, inp, inp->inp_label);
177 }
178 
179 void
180 mac_ipq_reassemble(struct ipq *q, struct mbuf *m)
181 {
182 	struct label *label;
183 
184 	label = mac_mbuf_to_label(m);
185 
186 	MAC_PERFORM(ipq_reassemble, q, q->ipq_label, m, label);
187 }
188 
189 void
190 mac_netinet_fragment(struct mbuf *m, struct mbuf *frag)
191 {
192 	struct label *mlabel, *fraglabel;
193 
194 	mlabel = mac_mbuf_to_label(m);
195 	fraglabel = mac_mbuf_to_label(frag);
196 
197 	MAC_PERFORM(netinet_fragment, m, mlabel, frag, fraglabel);
198 }
199 
200 void
201 mac_ipq_create(struct mbuf *m, struct ipq *q)
202 {
203 	struct label *label;
204 
205 	label = mac_mbuf_to_label(m);
206 
207 	MAC_PERFORM(ipq_create, m, label, q, q->ipq_label);
208 }
209 
210 void
211 mac_inpcb_create_mbuf(struct inpcb *inp, struct mbuf *m)
212 {
213 	struct label *mlabel;
214 
215 	INP_LOCK_ASSERT(inp);
216 	mlabel = mac_mbuf_to_label(m);
217 
218 	MAC_PERFORM(inpcb_create_mbuf, inp, inp->inp_label, m, mlabel);
219 }
220 
221 int
222 mac_ipq_match(struct mbuf *m, struct ipq *q)
223 {
224 	struct label *label;
225 	int result;
226 
227 	label = mac_mbuf_to_label(m);
228 
229 	result = 1;
230 	MAC_BOOLEAN(ipq_match, &&, m, label, q, q->ipq_label);
231 
232 	return (result);
233 }
234 
235 void
236 mac_netinet_arp_send(struct ifnet *ifp, struct mbuf *m)
237 {
238 	struct label *mlabel;
239 
240 	mlabel = mac_mbuf_to_label(m);
241 
242 	MAC_IFNET_LOCK(ifp);
243 	MAC_PERFORM(netinet_arp_send, ifp, ifp->if_label, m, mlabel);
244 	MAC_IFNET_UNLOCK(ifp);
245 }
246 
247 void
248 mac_netinet_icmp_reply(struct mbuf *mrecv, struct mbuf *msend)
249 {
250 	struct label *mrecvlabel, *msendlabel;
251 
252 	mrecvlabel = mac_mbuf_to_label(mrecv);
253 	msendlabel = mac_mbuf_to_label(msend);
254 
255 	MAC_PERFORM(netinet_icmp_reply, mrecv, mrecvlabel, msend,
256 	    msendlabel);
257 }
258 
259 void
260 mac_netinet_icmp_replyinplace(struct mbuf *m)
261 {
262 	struct label *label;
263 
264 	label = mac_mbuf_to_label(m);
265 
266 	MAC_PERFORM(netinet_icmp_replyinplace, m, label);
267 }
268 
269 void
270 mac_netinet_igmp_send(struct ifnet *ifp, struct mbuf *m)
271 {
272 	struct label *mlabel;
273 
274 	mlabel = mac_mbuf_to_label(m);
275 
276 	MAC_IFNET_LOCK(ifp);
277 	MAC_PERFORM(netinet_igmp_send, ifp, ifp->if_label, m, mlabel);
278 	MAC_IFNET_UNLOCK(ifp);
279 }
280 
281 void
282 mac_netinet_tcp_reply(struct mbuf *m)
283 {
284 	struct label *label;
285 
286 	label = mac_mbuf_to_label(m);
287 
288 	MAC_PERFORM(netinet_tcp_reply, m, label);
289 }
290 
291 void
292 mac_ipq_update(struct mbuf *m, struct ipq *q)
293 {
294 	struct label *label;
295 
296 	label = mac_mbuf_to_label(m);
297 
298 	MAC_PERFORM(ipq_update, m, label, q, q->ipq_label);
299 }
300 
301 int
302 mac_inpcb_check_deliver(struct inpcb *inp, struct mbuf *m)
303 {
304 	struct label *label;
305 	int error;
306 
307 	M_ASSERTPKTHDR(m);
308 
309 	label = mac_mbuf_to_label(m);
310 
311 	MAC_CHECK(inpcb_check_deliver, inp, inp->inp_label, m, label);
312 
313 	return (error);
314 }
315 
316 int
317 mac_inpcb_check_visible(struct ucred *cred, struct inpcb *inp)
318 {
319 	int error;
320 
321 	INP_LOCK_ASSERT(inp);
322 
323 	MAC_CHECK(inpcb_check_visible, cred, inp, inp->inp_label);
324 
325 	return (error);
326 }
327 
328 void
329 mac_inpcb_sosetlabel(struct socket *so, struct inpcb *inp)
330 {
331 
332 	INP_WLOCK_ASSERT(inp);
333 	SOCK_LOCK_ASSERT(so);
334 	MAC_PERFORM(inpcb_sosetlabel, so, so->so_label, inp, inp->inp_label);
335 }
336 
337 void
338 mac_netinet_firewall_reply(struct mbuf *mrecv, struct mbuf *msend)
339 {
340 	struct label *mrecvlabel, *msendlabel;
341 
342 	M_ASSERTPKTHDR(mrecv);
343 	M_ASSERTPKTHDR(msend);
344 
345 	mrecvlabel = mac_mbuf_to_label(mrecv);
346 	msendlabel = mac_mbuf_to_label(msend);
347 
348 	MAC_PERFORM(netinet_firewall_reply, mrecv, mrecvlabel, msend,
349 	    msendlabel);
350 }
351 
352 void
353 mac_netinet_firewall_send(struct mbuf *m)
354 {
355 	struct label *label;
356 
357 	M_ASSERTPKTHDR(m);
358 	label = mac_mbuf_to_label(m);
359 	MAC_PERFORM(netinet_firewall_send, m, label);
360 }
361 
362 /*
363  * These functions really should be referencing the syncache structure
364  * instead of the label.  However, due to some of the complexities associated
365  * with exposing this syncache structure we operate directly on it's label
366  * pointer.  This should be OK since we aren't making any access control
367  * decisions within this code directly, we are merely allocating and copying
368  * label storage so we can properly initialize mbuf labels for any packets
369  * the syncache code might create.
370  */
371 void
372 mac_syncache_destroy(struct label **label)
373 {
374 
375 	if (*label != NULL) {
376 		MAC_PERFORM(syncache_destroy_label, *label);
377 		mac_labelzone_free(*label);
378 		*label = NULL;
379 	}
380 }
381 
382 int
383 mac_syncache_init(struct label **label)
384 {
385 	int error;
386 
387 	if (mac_labeled & MPC_OBJECT_SYNCACHE) {
388 		*label = mac_labelzone_alloc(M_NOWAIT);
389 		if (*label == NULL)
390 			return (ENOMEM);
391 		/*
392 		 * Since we are holding the inpcb locks the policy can not
393 		 * allocate policy specific label storage using M_WAITOK.  So
394 		 * we need to do a MAC_CHECK instead of the typical
395 		 * MAC_PERFORM so we can propagate allocation failures back
396 		 * to the syncache code.
397 		 */
398 		MAC_CHECK(syncache_init_label, *label, M_NOWAIT);
399 		if (error) {
400 			MAC_PERFORM(syncache_destroy_label, *label);
401 			mac_labelzone_free(*label);
402 		}
403 		return (error);
404 	} else
405 		*label = NULL;
406 	return (0);
407 }
408 
409 void
410 mac_syncache_create(struct label *label, struct inpcb *inp)
411 {
412 
413 	INP_WLOCK_ASSERT(inp);
414 	MAC_PERFORM(syncache_create, label, inp);
415 }
416 
417 void
418 mac_syncache_create_mbuf(struct label *sc_label, struct mbuf *m)
419 {
420 	struct label *mlabel;
421 
422 	M_ASSERTPKTHDR(m);
423 	mlabel = mac_mbuf_to_label(m);
424 	MAC_PERFORM(syncache_create_mbuf, sc_label, m, mlabel);
425 }
426