2 * Copyright (c) 1999-2002 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5 * Copyright (c) 2005 SPARTA, Inc.
8 * This software was developed by Robert Watson and Ilmar Habibulin for the
11 * This software was developed for the FreeBSD Project in part by McAfee
12 * Research, the Technology Research Division of Network Associates, Inc.
13 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
14 * DARPA CHATS research program.
16 * This software was enhanced by SPARTA ISSO under SPAWAR contract
17 * N66001-04-C-6019 ("SEFOS").
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
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.
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
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
46 #include <sys/param.h>
47 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/mutex.h>
53 #include <sys/systm.h>
54 #include <sys/mount.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>
62 #include <net/bpfdesc.h>
64 #include <net/if_var.h>
66 #include <netinet/in.h>
67 #include <netinet/in_pcb.h>
68 #include <netinet/ip_var.h>
70 #include <security/mac/mac_framework.h>
71 #include <security/mac/mac_internal.h>
72 #include <security/mac/mac_policy.h>
75 * Currently, sockets hold two labels: the label of the socket itself, and a
76 * peer label, which may be used by policies to hold a copy of the label of
77 * any remote endpoint.
79 * Possibly, this peer label should be maintained at the protocol layer
80 * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
81 * the label consistently. For example, it might be copied live from a
82 * remote socket for UNIX domain sockets rather than keeping a local copy on
83 * this endpoint, but be cached and updated based on packets received for
88 mac_socket_label_alloc(int flag)
93 label = mac_labelzone_alloc(flag);
97 MAC_CHECK(init_socket_label, label, flag);
99 MAC_PERFORM(destroy_socket_label, label);
100 mac_labelzone_free(label);
106 static struct label *
107 mac_socket_peer_label_alloc(int flag)
112 label = mac_labelzone_alloc(flag);
116 MAC_CHECK(init_socket_peer_label, label, flag);
118 MAC_PERFORM(destroy_socket_peer_label, label);
119 mac_labelzone_free(label);
126 mac_init_socket(struct socket *so, int flag)
129 so->so_label = mac_socket_label_alloc(flag);
130 if (so->so_label == NULL)
132 so->so_peerlabel = mac_socket_peer_label_alloc(flag);
133 if (so->so_peerlabel == NULL) {
134 mac_socket_label_free(so->so_label);
142 mac_socket_label_free(struct label *label)
145 MAC_PERFORM(destroy_socket_label, label);
146 mac_labelzone_free(label);
150 mac_socket_peer_label_free(struct label *label)
153 MAC_PERFORM(destroy_socket_peer_label, label);
154 mac_labelzone_free(label);
158 mac_destroy_socket(struct socket *so)
161 mac_socket_label_free(so->so_label);
163 mac_socket_peer_label_free(so->so_peerlabel);
164 so->so_peerlabel = NULL;
168 mac_copy_socket_label(struct label *src, struct label *dest)
171 MAC_PERFORM(copy_socket_label, src, dest);
175 mac_externalize_socket_label(struct label *label, char *elements,
176 char *outbuf, size_t outbuflen)
180 MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
186 mac_externalize_socket_peer_label(struct label *label, char *elements,
187 char *outbuf, size_t outbuflen)
191 MAC_EXTERNALIZE(socket_peer, label, elements, outbuf, outbuflen);
197 mac_internalize_socket_label(struct label *label, char *string)
201 MAC_INTERNALIZE(socket, label, string);
207 mac_create_socket(struct ucred *cred, struct socket *so)
210 MAC_PERFORM(create_socket, cred, so, so->so_label);
214 mac_create_socket_from_socket(struct socket *oldso, struct socket *newso)
217 SOCK_LOCK_ASSERT(oldso);
219 MAC_PERFORM(create_socket_from_socket, oldso, oldso->so_label, newso,
224 mac_relabel_socket(struct ucred *cred, struct socket *so,
225 struct label *newlabel)
228 SOCK_LOCK_ASSERT(so);
230 MAC_PERFORM(relabel_socket, cred, so, so->so_label, newlabel);
234 mac_set_socket_peer_from_mbuf(struct mbuf *m, struct socket *so)
238 SOCK_LOCK_ASSERT(so);
240 label = mac_mbuf_to_label(m);
242 MAC_PERFORM(set_socket_peer_from_mbuf, m, label, so,
247 mac_set_socket_peer_from_socket(struct socket *oldso, struct socket *newso)
251 * XXXRW: only hold the socket lock on one at a time, as one socket
252 * is the original, and one is the new. However, it's called in both
253 * directions, so we can't assert the lock here currently.
255 MAC_PERFORM(set_socket_peer_from_socket, oldso, oldso->so_label,
256 newso, newso->so_peerlabel);
260 mac_create_mbuf_from_socket(struct socket *so, struct mbuf *m)
264 SOCK_LOCK_ASSERT(so);
266 label = mac_mbuf_to_label(m);
268 MAC_PERFORM(create_mbuf_from_socket, so, so->so_label, m, label);
272 mac_check_socket_accept(struct ucred *cred, struct socket *so)
276 SOCK_LOCK_ASSERT(so);
278 MAC_CHECK(check_socket_accept, cred, so, so->so_label);
284 mac_check_socket_bind(struct ucred *ucred, struct socket *so,
289 SOCK_LOCK_ASSERT(so);
291 MAC_CHECK(check_socket_bind, ucred, so, so->so_label, sa);
297 mac_check_socket_connect(struct ucred *cred, struct socket *so,
302 SOCK_LOCK_ASSERT(so);
304 MAC_CHECK(check_socket_connect, cred, so, so->so_label, sa);
310 mac_check_socket_create(struct ucred *cred, int domain, int type, int proto)
314 MAC_CHECK(check_socket_create, cred, domain, type, proto);
320 mac_check_socket_deliver(struct socket *so, struct mbuf *m)
325 SOCK_LOCK_ASSERT(so);
327 label = mac_mbuf_to_label(m);
329 MAC_CHECK(check_socket_deliver, so, so->so_label, m, label);
335 mac_check_socket_listen(struct ucred *cred, struct socket *so)
339 SOCK_LOCK_ASSERT(so);
341 MAC_CHECK(check_socket_listen, cred, so, so->so_label);
347 mac_check_socket_poll(struct ucred *cred, struct socket *so)
351 SOCK_LOCK_ASSERT(so);
353 MAC_CHECK(check_socket_poll, cred, so, so->so_label);
359 mac_check_socket_receive(struct ucred *cred, struct socket *so)
363 SOCK_LOCK_ASSERT(so);
365 MAC_CHECK(check_socket_receive, cred, so, so->so_label);
371 mac_check_socket_relabel(struct ucred *cred, struct socket *so,
372 struct label *newlabel)
376 SOCK_LOCK_ASSERT(so);
378 MAC_CHECK(check_socket_relabel, cred, so, so->so_label, newlabel);
384 mac_check_socket_send(struct ucred *cred, struct socket *so)
388 SOCK_LOCK_ASSERT(so);
390 MAC_CHECK(check_socket_send, cred, so, so->so_label);
396 mac_check_socket_stat(struct ucred *cred, struct socket *so)
400 SOCK_LOCK_ASSERT(so);
402 MAC_CHECK(check_socket_stat, cred, so, so->so_label);
408 mac_check_socket_visible(struct ucred *cred, struct socket *so)
412 SOCK_LOCK_ASSERT(so);
414 MAC_CHECK(check_socket_visible, cred, so, so->so_label);
420 mac_socket_label_set(struct ucred *cred, struct socket *so,
426 * We acquire the socket lock when we perform the test and set, but
427 * have to release it as the pcb code needs to acquire the pcb lock,
428 * which will precede the socket lock in the lock order. However,
429 * this is fine, as any race will simply result in the inpcb being
430 * refreshed twice, but still consistently, as the inpcb code will
431 * acquire the socket lock before refreshing, holding both locks.
434 error = mac_check_socket_relabel(cred, so, label);
440 mac_relabel_socket(cred, so, label);
444 * If the protocol has expressed interest in socket layer changes,
445 * such as if it needs to propagate changes to a cached pcb label
446 * from the socket, notify it of the label change while holding the
449 if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
450 (so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
456 mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
458 struct label *intlabel;
462 error = mac_check_structmac_consistent(mac);
466 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
467 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
469 free(buffer, M_MACTEMP);
473 intlabel = mac_socket_label_alloc(M_WAITOK);
474 error = mac_internalize_socket_label(intlabel, buffer);
475 free(buffer, M_MACTEMP);
479 error = mac_socket_label_set(cred, so, intlabel);
481 mac_socket_label_free(intlabel);
486 mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
488 char *buffer, *elements;
489 struct label *intlabel;
492 error = mac_check_structmac_consistent(mac);
496 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
497 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
499 free(elements, M_MACTEMP);
503 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
504 intlabel = mac_socket_label_alloc(M_WAITOK);
506 mac_copy_socket_label(so->so_label, intlabel);
508 error = mac_externalize_socket_label(intlabel, elements, buffer,
510 mac_socket_label_free(intlabel);
512 error = copyout(buffer, mac->m_string, strlen(buffer)+1);
514 free(buffer, M_MACTEMP);
515 free(elements, M_MACTEMP);
521 mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
524 char *elements, *buffer;
525 struct label *intlabel;
528 error = mac_check_structmac_consistent(mac);
532 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
533 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
535 free(elements, M_MACTEMP);
539 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
540 intlabel = mac_socket_label_alloc(M_WAITOK);
542 mac_copy_socket_label(so->so_peerlabel, intlabel);
544 error = mac_externalize_socket_peer_label(intlabel, elements, buffer,
546 mac_socket_label_free(intlabel);
548 error = copyout(buffer, mac->m_string, strlen(buffer)+1);
550 free(buffer, M_MACTEMP);
551 free(elements, M_MACTEMP);