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