xref: /freebsd/sys/security/mac/mac_socket.c (revision c14172e3aeb860d8e071f75ac5698a6954fb69a8)
1 /*-
2  * Copyright (c) 1999-2002, 2009 Robert N. M. Watson
3  * Copyright (c) 2001 Ilmar S. Habibulin
4  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5  * Copyright (c) 2005-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 McAfee
13  * Research, the Technology Research Division of Network Associates, Inc.
14  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
15  * 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_kdtrace.h"
49 #include "opt_mac.h"
50 
51 #include <sys/param.h>
52 #include <sys/kernel.h>
53 #include <sys/lock.h>
54 #include <sys/malloc.h>
55 #include <sys/mutex.h>
56 #include <sys/mac.h>
57 #include <sys/sbuf.h>
58 #include <sys/sdt.h>
59 #include <sys/systm.h>
60 #include <sys/mount.h>
61 #include <sys/file.h>
62 #include <sys/namei.h>
63 #include <sys/protosw.h>
64 #include <sys/socket.h>
65 #include <sys/socketvar.h>
66 #include <sys/sysctl.h>
67 
68 #include <net/bpfdesc.h>
69 #include <net/if.h>
70 #include <net/if_var.h>
71 
72 #include <netinet/in.h>
73 #include <netinet/in_pcb.h>
74 #include <netinet/ip_var.h>
75 
76 #include <security/mac/mac_framework.h>
77 #include <security/mac/mac_internal.h>
78 #include <security/mac/mac_policy.h>
79 
80 /*
81  * Currently, sockets hold two labels: the label of the socket itself, and a
82  * peer label, which may be used by policies to hold a copy of the label of
83  * any remote endpoint.
84  *
85  * Possibly, this peer label should be maintained at the protocol layer
86  * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
87  * the label consistently.  For example, it might be copied live from a
88  * remote socket for UNIX domain sockets rather than keeping a local copy on
89  * this endpoint, but be cached and updated based on packets received for
90  * TCP/IP.
91  */
92 
93 struct label *
94 mac_socket_label_alloc(int flag)
95 {
96 	struct label *label;
97 	int error;
98 
99 	label = mac_labelzone_alloc(flag);
100 	if (label == NULL)
101 		return (NULL);
102 
103 	MAC_CHECK(socket_init_label, label, flag);
104 	if (error) {
105 		MAC_PERFORM(socket_destroy_label, label);
106 		mac_labelzone_free(label);
107 		return (NULL);
108 	}
109 	return (label);
110 }
111 
112 static struct label *
113 mac_socketpeer_label_alloc(int flag)
114 {
115 	struct label *label;
116 	int error;
117 
118 	label = mac_labelzone_alloc(flag);
119 	if (label == NULL)
120 		return (NULL);
121 
122 	MAC_CHECK(socketpeer_init_label, label, flag);
123 	if (error) {
124 		MAC_PERFORM(socketpeer_destroy_label, label);
125 		mac_labelzone_free(label);
126 		return (NULL);
127 	}
128 	return (label);
129 }
130 
131 int
132 mac_socket_init(struct socket *so, int flag)
133 {
134 
135 	if (mac_labeled & MPC_OBJECT_SOCKET) {
136 		so->so_label = mac_socket_label_alloc(flag);
137 		if (so->so_label == NULL)
138 			return (ENOMEM);
139 		so->so_peerlabel = mac_socketpeer_label_alloc(flag);
140 		if (so->so_peerlabel == NULL) {
141 			mac_socket_label_free(so->so_label);
142 			so->so_label = NULL;
143 			return (ENOMEM);
144 		}
145 	} else {
146 		so->so_label = NULL;
147 		so->so_peerlabel = NULL;
148 	}
149 	return (0);
150 }
151 
152 void
153 mac_socket_label_free(struct label *label)
154 {
155 
156 	MAC_PERFORM(socket_destroy_label, label);
157 	mac_labelzone_free(label);
158 }
159 
160 static void
161 mac_socketpeer_label_free(struct label *label)
162 {
163 
164 	MAC_PERFORM(socketpeer_destroy_label, label);
165 	mac_labelzone_free(label);
166 }
167 
168 void
169 mac_socket_destroy(struct socket *so)
170 {
171 
172 	if (so->so_label != NULL) {
173 		mac_socket_label_free(so->so_label);
174 		so->so_label = NULL;
175 		mac_socketpeer_label_free(so->so_peerlabel);
176 		so->so_peerlabel = NULL;
177 	}
178 }
179 
180 void
181 mac_socket_copy_label(struct label *src, struct label *dest)
182 {
183 
184 	MAC_PERFORM(socket_copy_label, src, dest);
185 }
186 
187 int
188 mac_socket_externalize_label(struct label *label, char *elements,
189     char *outbuf, size_t outbuflen)
190 {
191 	int error;
192 
193 	MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
194 
195 	return (error);
196 }
197 
198 static int
199 mac_socketpeer_externalize_label(struct label *label, char *elements,
200     char *outbuf, size_t outbuflen)
201 {
202 	int error;
203 
204 	MAC_EXTERNALIZE(socketpeer, label, elements, outbuf, outbuflen);
205 
206 	return (error);
207 }
208 
209 int
210 mac_socket_internalize_label(struct label *label, char *string)
211 {
212 	int error;
213 
214 	MAC_INTERNALIZE(socket, label, string);
215 
216 	return (error);
217 }
218 
219 void
220 mac_socket_create(struct ucred *cred, struct socket *so)
221 {
222 
223 	MAC_PERFORM(socket_create, cred, so, so->so_label);
224 }
225 
226 void
227 mac_socket_newconn(struct socket *oldso, struct socket *newso)
228 {
229 
230 	SOCK_LOCK_ASSERT(oldso);
231 
232 	MAC_PERFORM(socket_newconn, oldso, oldso->so_label, newso,
233 	    newso->so_label);
234 }
235 
236 static void
237 mac_socket_relabel(struct ucred *cred, struct socket *so,
238     struct label *newlabel)
239 {
240 
241 	SOCK_LOCK_ASSERT(so);
242 
243 	MAC_PERFORM(socket_relabel, cred, so, so->so_label, newlabel);
244 }
245 
246 void
247 mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
248 {
249 	struct label *label;
250 
251 	SOCK_LOCK_ASSERT(so);
252 
253 	label = mac_mbuf_to_label(m);
254 
255 	MAC_PERFORM(socketpeer_set_from_mbuf, m, label, so,
256 	    so->so_peerlabel);
257 }
258 
259 void
260 mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
261 {
262 
263 	/*
264 	 * XXXRW: only hold the socket lock on one at a time, as one socket
265 	 * is the original, and one is the new.  However, it's called in both
266 	 * directions, so we can't assert the lock here currently.
267 	 */
268 	MAC_PERFORM(socketpeer_set_from_socket, oldso, oldso->so_label,
269 	    newso, newso->so_peerlabel);
270 }
271 
272 void
273 mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
274 {
275 	struct label *label;
276 
277 	SOCK_LOCK_ASSERT(so);
278 
279 	label = mac_mbuf_to_label(m);
280 
281 	MAC_PERFORM(socket_create_mbuf, so, so->so_label, m, label);
282 }
283 
284 MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *",
285     "struct socket *");
286 
287 int
288 mac_socket_check_accept(struct ucred *cred, struct socket *so)
289 {
290 	int error;
291 
292 	SOCK_LOCK_ASSERT(so);
293 
294 	MAC_CHECK(socket_check_accept, cred, so, so->so_label);
295 	MAC_CHECK_PROBE2(socket_check_accept, error, cred, so);
296 
297 	return (error);
298 }
299 
300 MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *",
301     "struct socket *", "struct sockaddr *");
302 
303 int
304 mac_socket_check_bind(struct ucred *cred, struct socket *so,
305     struct sockaddr *sa)
306 {
307 	int error;
308 
309 	SOCK_LOCK_ASSERT(so);
310 
311 	MAC_CHECK(socket_check_bind, cred, so, so->so_label, sa);
312 	MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa);
313 
314 	return (error);
315 }
316 
317 MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *",
318     "struct socket *", "struct sockaddr *");
319 
320 int
321 mac_socket_check_connect(struct ucred *cred, struct socket *so,
322     struct sockaddr *sa)
323 {
324 	int error;
325 
326 	SOCK_LOCK_ASSERT(so);
327 
328 	MAC_CHECK(socket_check_connect, cred, so, so->so_label, sa);
329 	MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa);
330 
331 	return (error);
332 }
333 
334 MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int",
335     "int");
336 
337 int
338 mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
339 {
340 	int error;
341 
342 	MAC_CHECK(socket_check_create, cred, domain, type, proto);
343 	MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type,
344 	    proto);
345 
346 	return (error);
347 }
348 
349 MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *",
350     "struct mbuf *");
351 
352 int
353 mac_socket_check_deliver(struct socket *so, struct mbuf *m)
354 {
355 	struct label *label;
356 	int error;
357 
358 	SOCK_LOCK_ASSERT(so);
359 
360 	label = mac_mbuf_to_label(m);
361 
362 	MAC_CHECK(socket_check_deliver, so, so->so_label, m, label);
363 	MAC_CHECK_PROBE2(socket_check_deliver, error, so, m);
364 
365 	return (error);
366 }
367 
368 MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *",
369     "struct socket *");
370 
371 int
372 mac_socket_check_listen(struct ucred *cred, struct socket *so)
373 {
374 	int error;
375 
376 	SOCK_LOCK_ASSERT(so);
377 
378 	MAC_CHECK(socket_check_listen, cred, so, so->so_label);
379 	MAC_CHECK_PROBE2(socket_check_listen, error, cred, so);
380 
381 	return (error);
382 }
383 
384 MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *",
385     "struct socket *");
386 
387 int
388 mac_socket_check_poll(struct ucred *cred, struct socket *so)
389 {
390 	int error;
391 
392 	SOCK_LOCK_ASSERT(so);
393 
394 	MAC_CHECK(socket_check_poll, cred, so, so->so_label);
395 	MAC_CHECK_PROBE2(socket_check_poll, error, cred, so);
396 
397 	return (error);
398 }
399 
400 MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *",
401     "struct socket *");
402 
403 int
404 mac_socket_check_receive(struct ucred *cred, struct socket *so)
405 {
406 	int error;
407 
408 	SOCK_LOCK_ASSERT(so);
409 
410 	MAC_CHECK(socket_check_receive, cred, so, so->so_label);
411 	MAC_CHECK_PROBE2(socket_check_receive, error, cred, so);
412 
413 	return (error);
414 }
415 
416 MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *",
417     "struct socket *", "struct label *");
418 
419 static int
420 mac_socket_check_relabel(struct ucred *cred, struct socket *so,
421     struct label *newlabel)
422 {
423 	int error;
424 
425 	SOCK_LOCK_ASSERT(so);
426 
427 	MAC_CHECK(socket_check_relabel, cred, so, so->so_label, newlabel);
428 	MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel);
429 
430 	return (error);
431 }
432 
433 MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *",
434     "struct socket *");
435 
436 int
437 mac_socket_check_send(struct ucred *cred, struct socket *so)
438 {
439 	int error;
440 
441 	SOCK_LOCK_ASSERT(so);
442 
443 	MAC_CHECK(socket_check_send, cred, so, so->so_label);
444 	MAC_CHECK_PROBE2(socket_check_send, error, cred, so);
445 
446 	return (error);
447 }
448 
449 MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *",
450     "struct socket *");
451 
452 int
453 mac_socket_check_stat(struct ucred *cred, struct socket *so)
454 {
455 	int error;
456 
457 	SOCK_LOCK_ASSERT(so);
458 
459 	MAC_CHECK(socket_check_stat, cred, so, so->so_label);
460 	MAC_CHECK_PROBE2(socket_check_stat, error, cred, so);
461 
462 	return (error);
463 }
464 
465 MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *",
466     "struct socket *");
467 
468 int
469 mac_socket_check_visible(struct ucred *cred, struct socket *so)
470 {
471 	int error;
472 
473 	SOCK_LOCK_ASSERT(so);
474 
475 	MAC_CHECK(socket_check_visible, cred, so, so->so_label);
476 	MAC_CHECK_PROBE2(socket_check_visible, error, cred, so);
477 
478 	return (error);
479 }
480 
481 int
482 mac_socket_label_set(struct ucred *cred, struct socket *so,
483     struct label *label)
484 {
485 	int error;
486 
487 	/*
488 	 * We acquire the socket lock when we perform the test and set, but
489 	 * have to release it as the pcb code needs to acquire the pcb lock,
490 	 * which will precede the socket lock in the lock order.  However,
491 	 * this is fine, as any race will simply result in the inpcb being
492 	 * refreshed twice, but still consistently, as the inpcb code will
493 	 * acquire the socket lock before refreshing, holding both locks.
494 	 */
495 	SOCK_LOCK(so);
496 	error = mac_socket_check_relabel(cred, so, label);
497 	if (error) {
498 		SOCK_UNLOCK(so);
499 		return (error);
500 	}
501 
502 	mac_socket_relabel(cred, so, label);
503 	SOCK_UNLOCK(so);
504 
505 	/*
506 	 * If the protocol has expressed interest in socket layer changes,
507 	 * such as if it needs to propagate changes to a cached pcb label
508 	 * from the socket, notify it of the label change while holding the
509 	 * socket lock.
510 	 */
511 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
512 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
513 
514 	return (0);
515 }
516 
517 int
518 mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
519 {
520 	struct label *intlabel;
521 	char *buffer;
522 	int error;
523 
524 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
525 		return (EINVAL);
526 
527 	error = mac_check_structmac_consistent(mac);
528 	if (error)
529 		return (error);
530 
531 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
532 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
533 	if (error) {
534 		free(buffer, M_MACTEMP);
535 		return (error);
536 	}
537 
538 	intlabel = mac_socket_label_alloc(M_WAITOK);
539 	error = mac_socket_internalize_label(intlabel, buffer);
540 	free(buffer, M_MACTEMP);
541 	if (error)
542 		goto out;
543 
544 	error = mac_socket_label_set(cred, so, intlabel);
545 out:
546 	mac_socket_label_free(intlabel);
547 	return (error);
548 }
549 
550 int
551 mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
552 {
553 	char *buffer, *elements;
554 	struct label *intlabel;
555 	int error;
556 
557 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
558 		return (EINVAL);
559 
560 	error = mac_check_structmac_consistent(mac);
561 	if (error)
562 		return (error);
563 
564 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
565 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
566 	if (error) {
567 		free(elements, M_MACTEMP);
568 		return (error);
569 	}
570 
571 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
572 	intlabel = mac_socket_label_alloc(M_WAITOK);
573 	SOCK_LOCK(so);
574 	mac_socket_copy_label(so->so_label, intlabel);
575 	SOCK_UNLOCK(so);
576 	error = mac_socket_externalize_label(intlabel, elements, buffer,
577 	    mac->m_buflen);
578 	mac_socket_label_free(intlabel);
579 	if (error == 0)
580 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
581 
582 	free(buffer, M_MACTEMP);
583 	free(elements, M_MACTEMP);
584 
585 	return (error);
586 }
587 
588 int
589 mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
590     struct mac *mac)
591 {
592 	char *elements, *buffer;
593 	struct label *intlabel;
594 	int error;
595 
596 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
597 		return (EINVAL);
598 
599 	error = mac_check_structmac_consistent(mac);
600 	if (error)
601 		return (error);
602 
603 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
604 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
605 	if (error) {
606 		free(elements, M_MACTEMP);
607 		return (error);
608 	}
609 
610 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
611 	intlabel = mac_socket_label_alloc(M_WAITOK);
612 	SOCK_LOCK(so);
613 	mac_socket_copy_label(so->so_peerlabel, intlabel);
614 	SOCK_UNLOCK(so);
615 	error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
616 	    mac->m_buflen);
617 	mac_socket_label_free(intlabel);
618 	if (error == 0)
619 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
620 
621 	free(buffer, M_MACTEMP);
622 	free(elements, M_MACTEMP);
623 
624 	return (error);
625 }
626