xref: /freebsd/sys/security/mac/mac_socket.c (revision f93bfb23dcb5b1d8a3aa13da522369974fcda39b)
1c66b4d8dSRobert Watson /*-
22087a58cSRobert Watson  * Copyright (c) 1999-2002, 2009 Robert N. M. Watson
3c66b4d8dSRobert Watson  * Copyright (c) 2001 Ilmar S. Habibulin
47f53207bSRobert Watson  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
530d239bcSRobert Watson  * Copyright (c) 2005-2006 SPARTA, Inc.
66356dba0SRobert Watson  * Copyright (c) 2008 Apple Inc.
7c66b4d8dSRobert Watson  * All rights reserved.
8c66b4d8dSRobert Watson  *
9c66b4d8dSRobert Watson  * This software was developed by Robert Watson and Ilmar Habibulin for the
10c66b4d8dSRobert Watson  * TrustedBSD Project.
11c66b4d8dSRobert Watson  *
127f53207bSRobert Watson  * This software was developed for the FreeBSD Project in part by McAfee
137f53207bSRobert Watson  * Research, the Technology Research Division of Network Associates, Inc.
147f53207bSRobert Watson  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
157f53207bSRobert Watson  * DARPA CHATS research program.
16c66b4d8dSRobert Watson  *
176758f88eSRobert Watson  * This software was enhanced by SPARTA ISSO under SPAWAR contract
186758f88eSRobert Watson  * N66001-04-C-6019 ("SEFOS").
196758f88eSRobert Watson  *
202087a58cSRobert Watson  * This software was developed at the University of Cambridge Computer
212087a58cSRobert Watson  * Laboratory with support from a grant from Google, Inc.
222087a58cSRobert Watson  *
23c66b4d8dSRobert Watson  * Redistribution and use in source and binary forms, with or without
24c66b4d8dSRobert Watson  * modification, are permitted provided that the following conditions
25c66b4d8dSRobert Watson  * are met:
26c66b4d8dSRobert Watson  * 1. Redistributions of source code must retain the above copyright
27c66b4d8dSRobert Watson  *    notice, this list of conditions and the following disclaimer.
28c66b4d8dSRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
29c66b4d8dSRobert Watson  *    notice, this list of conditions and the following disclaimer in the
30c66b4d8dSRobert Watson  *    documentation and/or other materials provided with the distribution.
31c66b4d8dSRobert Watson  *
32c66b4d8dSRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33c66b4d8dSRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34c66b4d8dSRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35c66b4d8dSRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36c66b4d8dSRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37c66b4d8dSRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38c66b4d8dSRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39c66b4d8dSRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40c66b4d8dSRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41c66b4d8dSRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42c66b4d8dSRobert Watson  * SUCH DAMAGE.
43c66b4d8dSRobert Watson  */
44c66b4d8dSRobert Watson 
45c66b4d8dSRobert Watson #include <sys/cdefs.h>
46c66b4d8dSRobert Watson __FBSDID("$FreeBSD$");
47c66b4d8dSRobert Watson 
482087a58cSRobert Watson #include "opt_kdtrace.h"
49c66b4d8dSRobert Watson #include "opt_mac.h"
50c66b4d8dSRobert Watson 
51c66b4d8dSRobert Watson #include <sys/param.h>
52c66b4d8dSRobert Watson #include <sys/kernel.h>
53c66b4d8dSRobert Watson #include <sys/lock.h>
54c66b4d8dSRobert Watson #include <sys/malloc.h>
55c66b4d8dSRobert Watson #include <sys/mutex.h>
56c66b4d8dSRobert Watson #include <sys/mac.h>
57c66b4d8dSRobert Watson #include <sys/sbuf.h>
582087a58cSRobert Watson #include <sys/sdt.h>
59c66b4d8dSRobert Watson #include <sys/systm.h>
60c66b4d8dSRobert Watson #include <sys/mount.h>
61c66b4d8dSRobert Watson #include <sys/file.h>
62c66b4d8dSRobert Watson #include <sys/namei.h>
63c66b4d8dSRobert Watson #include <sys/protosw.h>
64c66b4d8dSRobert Watson #include <sys/socket.h>
65c66b4d8dSRobert Watson #include <sys/socketvar.h>
66c66b4d8dSRobert Watson #include <sys/sysctl.h>
67c66b4d8dSRobert Watson 
68c66b4d8dSRobert Watson #include <net/bpfdesc.h>
69c66b4d8dSRobert Watson #include <net/if.h>
70c66b4d8dSRobert Watson #include <net/if_var.h>
71c66b4d8dSRobert Watson 
72c66b4d8dSRobert Watson #include <netinet/in.h>
73c66b4d8dSRobert Watson #include <netinet/in_pcb.h>
74c66b4d8dSRobert Watson #include <netinet/ip_var.h>
75c66b4d8dSRobert Watson 
76aed55708SRobert Watson #include <security/mac/mac_framework.h>
77c66b4d8dSRobert Watson #include <security/mac/mac_internal.h>
780efd6615SRobert Watson #include <security/mac/mac_policy.h>
79c66b4d8dSRobert Watson 
80c66b4d8dSRobert Watson /*
81df3c68e4SRobert Watson  * Currently, sockets hold two labels: the label of the socket itself, and a
82df3c68e4SRobert Watson  * peer label, which may be used by policies to hold a copy of the label of
83df3c68e4SRobert Watson  * any remote endpoint.
84df3c68e4SRobert Watson  *
85df3c68e4SRobert Watson  * Possibly, this peer label should be maintained at the protocol layer
86df3c68e4SRobert Watson  * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
87df3c68e4SRobert Watson  * the label consistently.  For example, it might be copied live from a
88df3c68e4SRobert Watson  * remote socket for UNIX domain sockets rather than keeping a local copy on
89df3c68e4SRobert Watson  * this endpoint, but be cached and updated based on packets received for
90df3c68e4SRobert Watson  * TCP/IP.
91df3c68e4SRobert Watson  */
92df3c68e4SRobert Watson 
93c66b4d8dSRobert Watson struct label *
94c66b4d8dSRobert Watson mac_socket_label_alloc(int flag)
95c66b4d8dSRobert Watson {
96c66b4d8dSRobert Watson 	struct label *label;
97c66b4d8dSRobert Watson 	int error;
98c66b4d8dSRobert Watson 
99c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
100c66b4d8dSRobert Watson 	if (label == NULL)
101c66b4d8dSRobert Watson 		return (NULL);
102c66b4d8dSRobert Watson 
10340202729SRobert Watson 	if (flag & M_WAITOK)
104fa765671SRobert Watson 		MAC_POLICY_CHECK(socket_init_label, label, flag);
10540202729SRobert Watson 	else
106fa765671SRobert Watson 		MAC_POLICY_CHECK_NOSLEEP(socket_init_label, label, flag);
107c66b4d8dSRobert Watson 	if (error) {
108fa765671SRobert Watson 		MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
109c66b4d8dSRobert Watson 		mac_labelzone_free(label);
110c66b4d8dSRobert Watson 		return (NULL);
111c66b4d8dSRobert Watson 	}
112c66b4d8dSRobert Watson 	return (label);
113c66b4d8dSRobert Watson }
114c66b4d8dSRobert Watson 
115c66b4d8dSRobert Watson static struct label *
11630d239bcSRobert Watson mac_socketpeer_label_alloc(int flag)
117c66b4d8dSRobert Watson {
118c66b4d8dSRobert Watson 	struct label *label;
119c66b4d8dSRobert Watson 	int error;
120c66b4d8dSRobert Watson 
121c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
122c66b4d8dSRobert Watson 	if (label == NULL)
123c66b4d8dSRobert Watson 		return (NULL);
124c66b4d8dSRobert Watson 
12540202729SRobert Watson 	if (flag & M_WAITOK)
126fa765671SRobert Watson 		MAC_POLICY_CHECK(socketpeer_init_label, label, flag);
12740202729SRobert Watson 	else
128fa765671SRobert Watson 		MAC_POLICY_CHECK_NOSLEEP(socketpeer_init_label, label, flag);
129c66b4d8dSRobert Watson 	if (error) {
130fa765671SRobert Watson 		MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
131c66b4d8dSRobert Watson 		mac_labelzone_free(label);
132c66b4d8dSRobert Watson 		return (NULL);
133c66b4d8dSRobert Watson 	}
134c66b4d8dSRobert Watson 	return (label);
135c66b4d8dSRobert Watson }
136c66b4d8dSRobert Watson 
137c66b4d8dSRobert Watson int
13830d239bcSRobert Watson mac_socket_init(struct socket *so, int flag)
139c66b4d8dSRobert Watson {
140c66b4d8dSRobert Watson 
1416356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_SOCKET) {
142c66b4d8dSRobert Watson 		so->so_label = mac_socket_label_alloc(flag);
143c66b4d8dSRobert Watson 		if (so->so_label == NULL)
144c66b4d8dSRobert Watson 			return (ENOMEM);
14530d239bcSRobert Watson 		so->so_peerlabel = mac_socketpeer_label_alloc(flag);
146c66b4d8dSRobert Watson 		if (so->so_peerlabel == NULL) {
147c66b4d8dSRobert Watson 			mac_socket_label_free(so->so_label);
148c66b4d8dSRobert Watson 			so->so_label = NULL;
149c66b4d8dSRobert Watson 			return (ENOMEM);
150c66b4d8dSRobert Watson 		}
1516356dba0SRobert Watson 	} else {
1526356dba0SRobert Watson 		so->so_label = NULL;
1536356dba0SRobert Watson 		so->so_peerlabel = NULL;
1546356dba0SRobert Watson 	}
155c66b4d8dSRobert Watson 	return (0);
156c66b4d8dSRobert Watson }
157c66b4d8dSRobert Watson 
158c66b4d8dSRobert Watson void
159c66b4d8dSRobert Watson mac_socket_label_free(struct label *label)
160c66b4d8dSRobert Watson {
161c66b4d8dSRobert Watson 
162fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
163c66b4d8dSRobert Watson 	mac_labelzone_free(label);
164c66b4d8dSRobert Watson }
165c66b4d8dSRobert Watson 
166c66b4d8dSRobert Watson static void
16730d239bcSRobert Watson mac_socketpeer_label_free(struct label *label)
168c66b4d8dSRobert Watson {
169c66b4d8dSRobert Watson 
170fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
171c66b4d8dSRobert Watson 	mac_labelzone_free(label);
172c66b4d8dSRobert Watson }
173c66b4d8dSRobert Watson 
174c66b4d8dSRobert Watson void
17530d239bcSRobert Watson mac_socket_destroy(struct socket *so)
176c66b4d8dSRobert Watson {
177c66b4d8dSRobert Watson 
1786356dba0SRobert Watson 	if (so->so_label != NULL) {
17926ae2b86SRobert Watson 		mac_socket_label_free(so->so_label);
18026ae2b86SRobert Watson 		so->so_label = NULL;
18130d239bcSRobert Watson 		mac_socketpeer_label_free(so->so_peerlabel);
18226ae2b86SRobert Watson 		so->so_peerlabel = NULL;
183c66b4d8dSRobert Watson 	}
1846356dba0SRobert Watson }
185c66b4d8dSRobert Watson 
186c66b4d8dSRobert Watson void
18730d239bcSRobert Watson mac_socket_copy_label(struct label *src, struct label *dest)
188c66b4d8dSRobert Watson {
189c66b4d8dSRobert Watson 
190fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest);
191c66b4d8dSRobert Watson }
192c66b4d8dSRobert Watson 
193c66b4d8dSRobert Watson int
19430d239bcSRobert Watson mac_socket_externalize_label(struct label *label, char *elements,
195c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
196c66b4d8dSRobert Watson {
197c66b4d8dSRobert Watson 	int error;
198c66b4d8dSRobert Watson 
199fa765671SRobert Watson 	MAC_POLICY_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
200c66b4d8dSRobert Watson 
201c66b4d8dSRobert Watson 	return (error);
202c66b4d8dSRobert Watson }
203c66b4d8dSRobert Watson 
204c66b4d8dSRobert Watson static int
20530d239bcSRobert Watson mac_socketpeer_externalize_label(struct label *label, char *elements,
206c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
207c66b4d8dSRobert Watson {
208c66b4d8dSRobert Watson 	int error;
209c66b4d8dSRobert Watson 
210fa765671SRobert Watson 	MAC_POLICY_EXTERNALIZE(socketpeer, label, elements, outbuf,
211fa765671SRobert Watson 	    outbuflen);
212c66b4d8dSRobert Watson 
213c66b4d8dSRobert Watson 	return (error);
214c66b4d8dSRobert Watson }
215c66b4d8dSRobert Watson 
216c66b4d8dSRobert Watson int
21730d239bcSRobert Watson mac_socket_internalize_label(struct label *label, char *string)
218c66b4d8dSRobert Watson {
219c66b4d8dSRobert Watson 	int error;
220c66b4d8dSRobert Watson 
221fa765671SRobert Watson 	MAC_POLICY_INTERNALIZE(socket, label, string);
222c66b4d8dSRobert Watson 
223c66b4d8dSRobert Watson 	return (error);
224c66b4d8dSRobert Watson }
225c66b4d8dSRobert Watson 
226c66b4d8dSRobert Watson void
22730d239bcSRobert Watson mac_socket_create(struct ucred *cred, struct socket *so)
228c66b4d8dSRobert Watson {
229c66b4d8dSRobert Watson 
230fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label);
231c66b4d8dSRobert Watson }
232c66b4d8dSRobert Watson 
233c66b4d8dSRobert Watson void
23430d239bcSRobert Watson mac_socket_newconn(struct socket *oldso, struct socket *newso)
235c66b4d8dSRobert Watson {
236c66b4d8dSRobert Watson 
237f93bfb23SRobert Watson 	if (mac_policy_count == 0)
238f93bfb23SRobert Watson 		return;
23926ae2b86SRobert Watson 
240f93bfb23SRobert Watson 	SOCK_LOCK(oldso);
241fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label,
242fa765671SRobert Watson 	    newso, newso->so_label);
243f93bfb23SRobert Watson 	SOCK_UNLOCK(oldso);
244c66b4d8dSRobert Watson }
245c66b4d8dSRobert Watson 
246c66b4d8dSRobert Watson static void
24730d239bcSRobert Watson mac_socket_relabel(struct ucred *cred, struct socket *so,
248c66b4d8dSRobert Watson     struct label *newlabel)
249c66b4d8dSRobert Watson {
250c66b4d8dSRobert Watson 
25126ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
25226ae2b86SRobert Watson 
253fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_relabel, cred, so, so->so_label,
25440202729SRobert Watson 	    newlabel);
255c66b4d8dSRobert Watson }
256c66b4d8dSRobert Watson 
257c66b4d8dSRobert Watson void
25830d239bcSRobert Watson mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
259c66b4d8dSRobert Watson {
260c66b4d8dSRobert Watson 	struct label *label;
261c66b4d8dSRobert Watson 
26226ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
263c66b4d8dSRobert Watson 
264f93bfb23SRobert Watson 	SOCK_LOCK(so);
265fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so,
26626ae2b86SRobert Watson 	    so->so_peerlabel);
267f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
268c66b4d8dSRobert Watson }
269c66b4d8dSRobert Watson 
270c66b4d8dSRobert Watson void
27130d239bcSRobert Watson mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
272c66b4d8dSRobert Watson {
273c66b4d8dSRobert Watson 
274f93bfb23SRobert Watson 	if (mac_policy_count == 0)
275f93bfb23SRobert Watson 		return;
276f93bfb23SRobert Watson 
277310e7cebSRobert Watson 	/*
278f93bfb23SRobert Watson 	 * XXXRW: We want to hold locks on both sockets, but can't currently
279f93bfb23SRobert Watson 	 * due to lock order -- opt to lock the socket where we're accessing
280f93bfb23SRobert Watson 	 * so_label as it's more likely to change.
281310e7cebSRobert Watson 	 */
282f93bfb23SRobert Watson 	SOCK_LOCK(oldso);
283fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso,
28440202729SRobert Watson 	    oldso->so_label, newso, newso->so_peerlabel);
285f93bfb23SRobert Watson 	SOCK_UNLOCK(oldso);
286c66b4d8dSRobert Watson }
287c66b4d8dSRobert Watson 
288c66b4d8dSRobert Watson void
28930d239bcSRobert Watson mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
290c66b4d8dSRobert Watson {
291c66b4d8dSRobert Watson 	struct label *label;
292c66b4d8dSRobert Watson 
293f93bfb23SRobert Watson 	if (mac_policy_count == 0)
294f93bfb23SRobert Watson 		return;
295c66b4d8dSRobert Watson 
29626ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
29726ae2b86SRobert Watson 
298f93bfb23SRobert Watson 	SOCK_LOCK(so);
299fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m,
300fa765671SRobert Watson 	    label);
301f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
302c66b4d8dSRobert Watson }
303c66b4d8dSRobert Watson 
3042087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *",
3052087a58cSRobert Watson     "struct socket *");
3062087a58cSRobert Watson 
307c66b4d8dSRobert Watson int
30830d239bcSRobert Watson mac_socket_check_accept(struct ucred *cred, struct socket *so)
3097f53207bSRobert Watson {
3107f53207bSRobert Watson 	int error;
3117f53207bSRobert Watson 
312f93bfb23SRobert Watson 	if (mac_policy_count == 0)
313f93bfb23SRobert Watson 		return (0);
3147f53207bSRobert Watson 
315f93bfb23SRobert Watson 	SOCK_LOCK(so);
316fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so,
317fa765671SRobert Watson 	    so->so_label);
3182087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_accept, error, cred, so);
319f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
3207f53207bSRobert Watson 
3217f53207bSRobert Watson 	return (error);
3227f53207bSRobert Watson }
3237f53207bSRobert Watson 
3242087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *",
3252087a58cSRobert Watson     "struct socket *", "struct sockaddr *");
3262087a58cSRobert Watson 
3277f53207bSRobert Watson int
328c14172e3SRobert Watson mac_socket_check_bind(struct ucred *cred, struct socket *so,
32926ae2b86SRobert Watson     struct sockaddr *sa)
330c66b4d8dSRobert Watson {
331c66b4d8dSRobert Watson 	int error;
332c66b4d8dSRobert Watson 
333f93bfb23SRobert Watson 	if (mac_policy_count == 0)
334f93bfb23SRobert Watson 		return (0);
335310e7cebSRobert Watson 
336f93bfb23SRobert Watson 	SOCK_LOCK(so);
337fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label,
338fa765671SRobert Watson 	    sa);
339c14172e3SRobert Watson 	MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa);
340f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
341c66b4d8dSRobert Watson 
342c66b4d8dSRobert Watson 	return (error);
343c66b4d8dSRobert Watson }
344c66b4d8dSRobert Watson 
3452087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *",
3462087a58cSRobert Watson     "struct socket *", "struct sockaddr *");
3472087a58cSRobert Watson 
348c66b4d8dSRobert Watson int
34930d239bcSRobert Watson mac_socket_check_connect(struct ucred *cred, struct socket *so,
35026ae2b86SRobert Watson     struct sockaddr *sa)
351c66b4d8dSRobert Watson {
352c66b4d8dSRobert Watson 	int error;
353c66b4d8dSRobert Watson 
354f93bfb23SRobert Watson 	if (mac_policy_count == 0)
355f93bfb23SRobert Watson 		return (0);
356310e7cebSRobert Watson 
357f93bfb23SRobert Watson 	SOCK_LOCK(so);
358fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so,
359fa765671SRobert Watson 	    so->so_label, sa);
3602087a58cSRobert Watson 	MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa);
361f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
362c66b4d8dSRobert Watson 
363c66b4d8dSRobert Watson 	return (error);
364c66b4d8dSRobert Watson }
365c66b4d8dSRobert Watson 
3662087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int",
3672087a58cSRobert Watson     "int");
3682087a58cSRobert Watson 
369c66b4d8dSRobert Watson int
37030d239bcSRobert Watson mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
3716758f88eSRobert Watson {
3726758f88eSRobert Watson 	int error;
3736758f88eSRobert Watson 
374fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_create, cred, domain, type,
375fa765671SRobert Watson 	    proto);
3762087a58cSRobert Watson 	MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type,
3772087a58cSRobert Watson 	    proto);
3786758f88eSRobert Watson 
3796758f88eSRobert Watson 	return (error);
3806758f88eSRobert Watson }
3816758f88eSRobert Watson 
3822087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *",
3832087a58cSRobert Watson     "struct mbuf *");
3842087a58cSRobert Watson 
3856758f88eSRobert Watson int
38630d239bcSRobert Watson mac_socket_check_deliver(struct socket *so, struct mbuf *m)
387c66b4d8dSRobert Watson {
388c66b4d8dSRobert Watson 	struct label *label;
389c66b4d8dSRobert Watson 	int error;
390c66b4d8dSRobert Watson 
391f93bfb23SRobert Watson 	if (mac_policy_count == 0)
392f93bfb23SRobert Watson 		return (0);
393310e7cebSRobert Watson 
39426ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
395c66b4d8dSRobert Watson 
396f93bfb23SRobert Watson 	SOCK_LOCK(so);
397fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m,
398fa765671SRobert Watson 	    label);
3992087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_deliver, error, so, m);
400f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
401c66b4d8dSRobert Watson 
402c66b4d8dSRobert Watson 	return (error);
403c66b4d8dSRobert Watson }
404c66b4d8dSRobert Watson 
4052087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *",
4062087a58cSRobert Watson     "struct socket *");
4072087a58cSRobert Watson 
408c66b4d8dSRobert Watson int
40930d239bcSRobert Watson mac_socket_check_listen(struct ucred *cred, struct socket *so)
410c66b4d8dSRobert Watson {
411c66b4d8dSRobert Watson 	int error;
412c66b4d8dSRobert Watson 
413f93bfb23SRobert Watson 	if (mac_policy_count == 0)
414f93bfb23SRobert Watson 		return (0);
415310e7cebSRobert Watson 
416f93bfb23SRobert Watson 	SOCK_LOCK(so);
417fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so,
418fa765671SRobert Watson 	    so->so_label);
4192087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_listen, error, cred, so);
420f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
42126ae2b86SRobert Watson 
422c66b4d8dSRobert Watson 	return (error);
423c66b4d8dSRobert Watson }
424c66b4d8dSRobert Watson 
4252087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *",
4262087a58cSRobert Watson     "struct socket *");
4272087a58cSRobert Watson 
428c66b4d8dSRobert Watson int
42930d239bcSRobert Watson mac_socket_check_poll(struct ucred *cred, struct socket *so)
4307f53207bSRobert Watson {
4317f53207bSRobert Watson 	int error;
4327f53207bSRobert Watson 
433f93bfb23SRobert Watson 	if (mac_policy_count == 0)
434f93bfb23SRobert Watson 		return (0);
4357f53207bSRobert Watson 
436f93bfb23SRobert Watson 	SOCK_LOCK(so);
437fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label);
4382087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_poll, error, cred, so);
439f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
44026ae2b86SRobert Watson 
4417f53207bSRobert Watson 	return (error);
4427f53207bSRobert Watson }
4437f53207bSRobert Watson 
4442087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *",
4452087a58cSRobert Watson     "struct socket *");
4462087a58cSRobert Watson 
4477f53207bSRobert Watson int
44830d239bcSRobert Watson mac_socket_check_receive(struct ucred *cred, struct socket *so)
449c66b4d8dSRobert Watson {
450c66b4d8dSRobert Watson 	int error;
451c66b4d8dSRobert Watson 
452f93bfb23SRobert Watson 	if (mac_policy_count == 0)
453f93bfb23SRobert Watson 		return (0);
454310e7cebSRobert Watson 
455f93bfb23SRobert Watson 	SOCK_LOCK(so);
456fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so,
457fa765671SRobert Watson 	    so->so_label);
4582087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_receive, error, cred, so);
459f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
460c66b4d8dSRobert Watson 
461c66b4d8dSRobert Watson 	return (error);
462c66b4d8dSRobert Watson }
463c66b4d8dSRobert Watson 
4642087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *",
4652087a58cSRobert Watson     "struct socket *", "struct label *");
4662087a58cSRobert Watson 
467c66b4d8dSRobert Watson static int
46830d239bcSRobert Watson mac_socket_check_relabel(struct ucred *cred, struct socket *so,
469c66b4d8dSRobert Watson     struct label *newlabel)
470c66b4d8dSRobert Watson {
471c66b4d8dSRobert Watson 	int error;
472c66b4d8dSRobert Watson 
47326ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
474310e7cebSRobert Watson 
475fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_relabel, cred, so,
476fa765671SRobert Watson 	    so->so_label, newlabel);
4772087a58cSRobert Watson 	MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel);
478c66b4d8dSRobert Watson 
479c66b4d8dSRobert Watson 	return (error);
480c66b4d8dSRobert Watson }
481c66b4d8dSRobert Watson 
4822087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *",
4832087a58cSRobert Watson     "struct socket *");
4842087a58cSRobert Watson 
485c66b4d8dSRobert Watson int
48630d239bcSRobert Watson mac_socket_check_send(struct ucred *cred, struct socket *so)
487c66b4d8dSRobert Watson {
488c66b4d8dSRobert Watson 	int error;
489c66b4d8dSRobert Watson 
490f93bfb23SRobert Watson 	if (mac_policy_count == 0)
491f93bfb23SRobert Watson 		return (0);
492310e7cebSRobert Watson 
493f93bfb23SRobert Watson 	SOCK_LOCK(so);
494fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label);
4952087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_send, error, cred, so);
496f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
497c66b4d8dSRobert Watson 
498c66b4d8dSRobert Watson 	return (error);
499c66b4d8dSRobert Watson }
500c66b4d8dSRobert Watson 
5012087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *",
5022087a58cSRobert Watson     "struct socket *");
5032087a58cSRobert Watson 
504c66b4d8dSRobert Watson int
50530d239bcSRobert Watson mac_socket_check_stat(struct ucred *cred, struct socket *so)
5067f53207bSRobert Watson {
5077f53207bSRobert Watson 	int error;
5087f53207bSRobert Watson 
509f93bfb23SRobert Watson 	if (mac_policy_count == 0)
510f93bfb23SRobert Watson 		return (0);
5117f53207bSRobert Watson 
512f93bfb23SRobert Watson 	SOCK_LOCK(so);
513fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label);
5142087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_stat, error, cred, so);
515f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
5167f53207bSRobert Watson 
5177f53207bSRobert Watson 	return (error);
5187f53207bSRobert Watson }
5197f53207bSRobert Watson 
5202087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *",
5212087a58cSRobert Watson     "struct socket *");
5222087a58cSRobert Watson 
5237f53207bSRobert Watson int
52430d239bcSRobert Watson mac_socket_check_visible(struct ucred *cred, struct socket *so)
525c66b4d8dSRobert Watson {
526c66b4d8dSRobert Watson 	int error;
527c66b4d8dSRobert Watson 
528f93bfb23SRobert Watson 	if (mac_policy_count == 0)
529f93bfb23SRobert Watson 		return (0);
530310e7cebSRobert Watson 
531f93bfb23SRobert Watson 	SOCK_LOCK(so);
532fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so,
533fa765671SRobert Watson 	    so->so_label);
5342087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_visible, error, cred, so);
535f93bfb23SRobert Watson 	SOCK_UNLOCK(so);
536c66b4d8dSRobert Watson 
537c66b4d8dSRobert Watson 	return (error);
538c66b4d8dSRobert Watson }
539c66b4d8dSRobert Watson 
540c66b4d8dSRobert Watson int
541c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so,
542c66b4d8dSRobert Watson     struct label *label)
543c66b4d8dSRobert Watson {
544c66b4d8dSRobert Watson 	int error;
545c66b4d8dSRobert Watson 
546310e7cebSRobert Watson 	/*
547df3c68e4SRobert Watson 	 * We acquire the socket lock when we perform the test and set, but
548df3c68e4SRobert Watson 	 * have to release it as the pcb code needs to acquire the pcb lock,
549df3c68e4SRobert Watson 	 * which will precede the socket lock in the lock order.  However,
550df3c68e4SRobert Watson 	 * this is fine, as any race will simply result in the inpcb being
551df3c68e4SRobert Watson 	 * refreshed twice, but still consistently, as the inpcb code will
552df3c68e4SRobert Watson 	 * acquire the socket lock before refreshing, holding both locks.
553310e7cebSRobert Watson 	 */
554310e7cebSRobert Watson 	SOCK_LOCK(so);
55530d239bcSRobert Watson 	error = mac_socket_check_relabel(cred, so, label);
556310e7cebSRobert Watson 	if (error) {
557310e7cebSRobert Watson 		SOCK_UNLOCK(so);
558c66b4d8dSRobert Watson 		return (error);
559310e7cebSRobert Watson 	}
560c66b4d8dSRobert Watson 
56130d239bcSRobert Watson 	mac_socket_relabel(cred, so, label);
562310e7cebSRobert Watson 	SOCK_UNLOCK(so);
563df3c68e4SRobert Watson 
564c66b4d8dSRobert Watson 	/*
565c66b4d8dSRobert Watson 	 * If the protocol has expressed interest in socket layer changes,
566df3c68e4SRobert Watson 	 * such as if it needs to propagate changes to a cached pcb label
567df3c68e4SRobert Watson 	 * from the socket, notify it of the label change while holding the
568df3c68e4SRobert Watson 	 * socket lock.
569c66b4d8dSRobert Watson 	 */
570c66b4d8dSRobert Watson 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
571c66b4d8dSRobert Watson 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
572c66b4d8dSRobert Watson 
573c66b4d8dSRobert Watson 	return (0);
574c66b4d8dSRobert Watson }
575c66b4d8dSRobert Watson 
576c66b4d8dSRobert Watson int
577c66b4d8dSRobert Watson mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
578c66b4d8dSRobert Watson {
579c66b4d8dSRobert Watson 	struct label *intlabel;
580c66b4d8dSRobert Watson 	char *buffer;
581c66b4d8dSRobert Watson 	int error;
582c66b4d8dSRobert Watson 
5836356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
5846356dba0SRobert Watson 		return (EINVAL);
5856356dba0SRobert Watson 
586c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
587c66b4d8dSRobert Watson 	if (error)
588c66b4d8dSRobert Watson 		return (error);
589c66b4d8dSRobert Watson 
590c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
591c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
592c66b4d8dSRobert Watson 	if (error) {
593c66b4d8dSRobert Watson 		free(buffer, M_MACTEMP);
594c66b4d8dSRobert Watson 		return (error);
595c66b4d8dSRobert Watson 	}
596c66b4d8dSRobert Watson 
597c66b4d8dSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
59830d239bcSRobert Watson 	error = mac_socket_internalize_label(intlabel, buffer);
599c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
600c66b4d8dSRobert Watson 	if (error)
601c66b4d8dSRobert Watson 		goto out;
602c66b4d8dSRobert Watson 
603c66b4d8dSRobert Watson 	error = mac_socket_label_set(cred, so, intlabel);
604c66b4d8dSRobert Watson out:
605c66b4d8dSRobert Watson 	mac_socket_label_free(intlabel);
606c66b4d8dSRobert Watson 	return (error);
607c66b4d8dSRobert Watson }
608c66b4d8dSRobert Watson 
609c66b4d8dSRobert Watson int
610c66b4d8dSRobert Watson mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
611c66b4d8dSRobert Watson {
612c66b4d8dSRobert Watson 	char *buffer, *elements;
613310e7cebSRobert Watson 	struct label *intlabel;
614c66b4d8dSRobert Watson 	int error;
615c66b4d8dSRobert Watson 
6166356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
6176356dba0SRobert Watson 		return (EINVAL);
6186356dba0SRobert Watson 
619c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
620c66b4d8dSRobert Watson 	if (error)
621c66b4d8dSRobert Watson 		return (error);
622c66b4d8dSRobert Watson 
623c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
624c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
625c66b4d8dSRobert Watson 	if (error) {
626c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
627c66b4d8dSRobert Watson 		return (error);
628c66b4d8dSRobert Watson 	}
629c66b4d8dSRobert Watson 
630c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
631310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
632310e7cebSRobert Watson 	SOCK_LOCK(so);
63330d239bcSRobert Watson 	mac_socket_copy_label(so->so_label, intlabel);
634310e7cebSRobert Watson 	SOCK_UNLOCK(so);
63530d239bcSRobert Watson 	error = mac_socket_externalize_label(intlabel, elements, buffer,
636310e7cebSRobert Watson 	    mac->m_buflen);
637310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
638c66b4d8dSRobert Watson 	if (error == 0)
639c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
640c66b4d8dSRobert Watson 
641c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
642c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
643c66b4d8dSRobert Watson 
644c66b4d8dSRobert Watson 	return (error);
645c66b4d8dSRobert Watson }
646c66b4d8dSRobert Watson 
647c66b4d8dSRobert Watson int
648c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
649c66b4d8dSRobert Watson     struct mac *mac)
650c66b4d8dSRobert Watson {
651c66b4d8dSRobert Watson 	char *elements, *buffer;
652310e7cebSRobert Watson 	struct label *intlabel;
653c66b4d8dSRobert Watson 	int error;
654c66b4d8dSRobert Watson 
6556356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
6566356dba0SRobert Watson 		return (EINVAL);
6576356dba0SRobert Watson 
658c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
659c66b4d8dSRobert Watson 	if (error)
660c66b4d8dSRobert Watson 		return (error);
661c66b4d8dSRobert Watson 
662c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
663c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
664c66b4d8dSRobert Watson 	if (error) {
665c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
666c66b4d8dSRobert Watson 		return (error);
667c66b4d8dSRobert Watson 	}
668c66b4d8dSRobert Watson 
669c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
670310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
671310e7cebSRobert Watson 	SOCK_LOCK(so);
67230d239bcSRobert Watson 	mac_socket_copy_label(so->so_peerlabel, intlabel);
673310e7cebSRobert Watson 	SOCK_UNLOCK(so);
67430d239bcSRobert Watson 	error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
675310e7cebSRobert Watson 	    mac->m_buflen);
676310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
677c66b4d8dSRobert Watson 	if (error == 0)
678c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
679c66b4d8dSRobert Watson 
680c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
681c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
682c66b4d8dSRobert Watson 
683c66b4d8dSRobert Watson 	return (error);
684c66b4d8dSRobert Watson }
685