xref: /freebsd/sys/security/mac/mac_socket.c (revision 2fb778fab893b4a8a86ecfa20acf2e23bb2cdae8)
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 #include "opt_mac.h"
47c66b4d8dSRobert Watson 
48c66b4d8dSRobert Watson #include <sys/param.h>
49c66b4d8dSRobert Watson #include <sys/kernel.h>
50c66b4d8dSRobert Watson #include <sys/lock.h>
51c66b4d8dSRobert Watson #include <sys/malloc.h>
52c66b4d8dSRobert Watson #include <sys/mutex.h>
53c66b4d8dSRobert Watson #include <sys/mac.h>
54c66b4d8dSRobert Watson #include <sys/sbuf.h>
552087a58cSRobert Watson #include <sys/sdt.h>
56c66b4d8dSRobert Watson #include <sys/systm.h>
57c66b4d8dSRobert Watson #include <sys/mount.h>
58c66b4d8dSRobert Watson #include <sys/file.h>
59c66b4d8dSRobert Watson #include <sys/namei.h>
60c66b4d8dSRobert Watson #include <sys/protosw.h>
61c66b4d8dSRobert Watson #include <sys/socket.h>
62c66b4d8dSRobert Watson #include <sys/socketvar.h>
63c66b4d8dSRobert Watson #include <sys/sysctl.h>
64c66b4d8dSRobert Watson 
65c66b4d8dSRobert Watson #include <net/bpfdesc.h>
66c66b4d8dSRobert Watson #include <net/if.h>
67c66b4d8dSRobert Watson #include <net/if_var.h>
68c66b4d8dSRobert Watson 
69c66b4d8dSRobert Watson #include <netinet/in.h>
70c66b4d8dSRobert Watson #include <netinet/in_pcb.h>
71c66b4d8dSRobert Watson #include <netinet/ip_var.h>
72c66b4d8dSRobert Watson 
73aed55708SRobert Watson #include <security/mac/mac_framework.h>
74c66b4d8dSRobert Watson #include <security/mac/mac_internal.h>
750efd6615SRobert Watson #include <security/mac/mac_policy.h>
76c66b4d8dSRobert Watson 
77c66b4d8dSRobert Watson /*
78df3c68e4SRobert Watson  * Currently, sockets hold two labels: the label of the socket itself, and a
79df3c68e4SRobert Watson  * peer label, which may be used by policies to hold a copy of the label of
80df3c68e4SRobert Watson  * any remote endpoint.
81df3c68e4SRobert Watson  *
82df3c68e4SRobert Watson  * Possibly, this peer label should be maintained at the protocol layer
83df3c68e4SRobert Watson  * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
84df3c68e4SRobert Watson  * the label consistently.  For example, it might be copied live from a
85df3c68e4SRobert Watson  * remote socket for UNIX domain sockets rather than keeping a local copy on
86df3c68e4SRobert Watson  * this endpoint, but be cached and updated based on packets received for
87df3c68e4SRobert Watson  * TCP/IP.
883de40469SRobert Watson  *
893de40469SRobert Watson  * Unlike with many other object types, the lock protecting MAC labels on
903de40469SRobert Watson  * sockets (the socket lock) is not frequently held at the points in code
913de40469SRobert Watson  * where socket-related checks are called.  The MAC Framework acquires the
923de40469SRobert Watson  * lock over some entry points in order to enforce atomicity (such as label
933de40469SRobert Watson  * copies) but in other cases the policy modules will have to acquire the
943de40469SRobert Watson  * lock themselves if they use labels.  This approach (a) avoids lock
953de40469SRobert Watson  * acquisitions when policies don't require labels and (b) solves a number of
963de40469SRobert Watson  * potential lock order issues when multiple sockets are used in the same
973de40469SRobert Watson  * entry point.
98df3c68e4SRobert Watson  */
99df3c68e4SRobert Watson 
100c66b4d8dSRobert Watson struct label *
mac_socket_label_alloc(int flag)101c66b4d8dSRobert Watson mac_socket_label_alloc(int flag)
102c66b4d8dSRobert Watson {
103c66b4d8dSRobert Watson 	struct label *label;
104c66b4d8dSRobert Watson 	int error;
105c66b4d8dSRobert Watson 
106c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
107c66b4d8dSRobert Watson 	if (label == NULL)
108c66b4d8dSRobert Watson 		return (NULL);
109c66b4d8dSRobert Watson 
11040202729SRobert Watson 	if (flag & M_WAITOK)
111fa765671SRobert Watson 		MAC_POLICY_CHECK(socket_init_label, label, flag);
11240202729SRobert Watson 	else
113fa765671SRobert Watson 		MAC_POLICY_CHECK_NOSLEEP(socket_init_label, label, flag);
114c66b4d8dSRobert Watson 	if (error) {
115fa765671SRobert Watson 		MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
116c66b4d8dSRobert Watson 		mac_labelzone_free(label);
117c66b4d8dSRobert Watson 		return (NULL);
118c66b4d8dSRobert Watson 	}
119c66b4d8dSRobert Watson 	return (label);
120c66b4d8dSRobert Watson }
121c66b4d8dSRobert Watson 
122c66b4d8dSRobert Watson static struct label *
mac_socketpeer_label_alloc(int flag)12330d239bcSRobert Watson mac_socketpeer_label_alloc(int flag)
124c66b4d8dSRobert Watson {
125c66b4d8dSRobert Watson 	struct label *label;
126c66b4d8dSRobert Watson 	int error;
127c66b4d8dSRobert Watson 
128c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
129c66b4d8dSRobert Watson 	if (label == NULL)
130c66b4d8dSRobert Watson 		return (NULL);
131c66b4d8dSRobert Watson 
13240202729SRobert Watson 	if (flag & M_WAITOK)
133fa765671SRobert Watson 		MAC_POLICY_CHECK(socketpeer_init_label, label, flag);
13440202729SRobert Watson 	else
135fa765671SRobert Watson 		MAC_POLICY_CHECK_NOSLEEP(socketpeer_init_label, label, flag);
136c66b4d8dSRobert Watson 	if (error) {
137fa765671SRobert Watson 		MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
138c66b4d8dSRobert Watson 		mac_labelzone_free(label);
139c66b4d8dSRobert Watson 		return (NULL);
140c66b4d8dSRobert Watson 	}
141c66b4d8dSRobert Watson 	return (label);
142c66b4d8dSRobert Watson }
143c66b4d8dSRobert Watson 
144c66b4d8dSRobert Watson int
mac_socket_init(struct socket * so,int flag)14530d239bcSRobert Watson mac_socket_init(struct socket *so, int flag)
146c66b4d8dSRobert Watson {
147c66b4d8dSRobert Watson 
1486356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_SOCKET) {
149c66b4d8dSRobert Watson 		so->so_label = mac_socket_label_alloc(flag);
150c66b4d8dSRobert Watson 		if (so->so_label == NULL)
151c66b4d8dSRobert Watson 			return (ENOMEM);
15230d239bcSRobert Watson 		so->so_peerlabel = mac_socketpeer_label_alloc(flag);
153c66b4d8dSRobert Watson 		if (so->so_peerlabel == NULL) {
154c66b4d8dSRobert Watson 			mac_socket_label_free(so->so_label);
155c66b4d8dSRobert Watson 			so->so_label = NULL;
156c66b4d8dSRobert Watson 			return (ENOMEM);
157c66b4d8dSRobert Watson 		}
1586356dba0SRobert Watson 	} else {
1596356dba0SRobert Watson 		so->so_label = NULL;
1606356dba0SRobert Watson 		so->so_peerlabel = NULL;
1616356dba0SRobert Watson 	}
162c66b4d8dSRobert Watson 	return (0);
163c66b4d8dSRobert Watson }
164c66b4d8dSRobert Watson 
165c66b4d8dSRobert Watson void
mac_socket_label_free(struct label * label)166c66b4d8dSRobert Watson mac_socket_label_free(struct label *label)
167c66b4d8dSRobert Watson {
168c66b4d8dSRobert Watson 
169fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
170c66b4d8dSRobert Watson 	mac_labelzone_free(label);
171c66b4d8dSRobert Watson }
172c66b4d8dSRobert Watson 
173*2fb778faSMichael Tuexen void
mac_socketpeer_label_free(struct label * label)17430d239bcSRobert Watson mac_socketpeer_label_free(struct label *label)
175c66b4d8dSRobert Watson {
176c66b4d8dSRobert Watson 
177fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
178c66b4d8dSRobert Watson 	mac_labelzone_free(label);
179c66b4d8dSRobert Watson }
180c66b4d8dSRobert Watson 
181c66b4d8dSRobert Watson void
mac_socket_destroy(struct socket * so)18230d239bcSRobert Watson mac_socket_destroy(struct socket *so)
183c66b4d8dSRobert Watson {
184c66b4d8dSRobert Watson 
1856356dba0SRobert Watson 	if (so->so_label != NULL) {
18626ae2b86SRobert Watson 		mac_socket_label_free(so->so_label);
18726ae2b86SRobert Watson 		so->so_label = NULL;
188*2fb778faSMichael Tuexen 		if (!SOLISTENING(so)) {
18930d239bcSRobert Watson 			mac_socketpeer_label_free(so->so_peerlabel);
19026ae2b86SRobert Watson 			so->so_peerlabel = NULL;
191c66b4d8dSRobert Watson 		}
1926356dba0SRobert Watson 	}
193*2fb778faSMichael Tuexen }
194c66b4d8dSRobert Watson 
195c66b4d8dSRobert Watson void
mac_socket_copy_label(struct label * src,struct label * dest)19630d239bcSRobert Watson mac_socket_copy_label(struct label *src, struct label *dest)
197c66b4d8dSRobert Watson {
198c66b4d8dSRobert Watson 
199fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest);
200c66b4d8dSRobert Watson }
201c66b4d8dSRobert Watson 
202c66b4d8dSRobert Watson int
mac_socket_externalize_label(struct label * label,char * elements,char * outbuf,size_t outbuflen)20330d239bcSRobert Watson mac_socket_externalize_label(struct label *label, char *elements,
204c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
205c66b4d8dSRobert Watson {
206c66b4d8dSRobert Watson 	int error;
207c66b4d8dSRobert Watson 
208fa765671SRobert Watson 	MAC_POLICY_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
209c66b4d8dSRobert Watson 
210c66b4d8dSRobert Watson 	return (error);
211c66b4d8dSRobert Watson }
212c66b4d8dSRobert Watson 
213c66b4d8dSRobert Watson static int
mac_socketpeer_externalize_label(struct label * label,char * elements,char * outbuf,size_t outbuflen)21430d239bcSRobert Watson mac_socketpeer_externalize_label(struct label *label, char *elements,
215c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
216c66b4d8dSRobert Watson {
217c66b4d8dSRobert Watson 	int error;
218c66b4d8dSRobert Watson 
219fa765671SRobert Watson 	MAC_POLICY_EXTERNALIZE(socketpeer, label, elements, outbuf,
220fa765671SRobert Watson 	    outbuflen);
221c66b4d8dSRobert Watson 
222c66b4d8dSRobert Watson 	return (error);
223c66b4d8dSRobert Watson }
224c66b4d8dSRobert Watson 
225c66b4d8dSRobert Watson int
mac_socket_internalize_label(struct label * label,char * string)22630d239bcSRobert Watson mac_socket_internalize_label(struct label *label, char *string)
227c66b4d8dSRobert Watson {
228c66b4d8dSRobert Watson 	int error;
229c66b4d8dSRobert Watson 
230fa765671SRobert Watson 	MAC_POLICY_INTERNALIZE(socket, label, string);
231c66b4d8dSRobert Watson 
232c66b4d8dSRobert Watson 	return (error);
233c66b4d8dSRobert Watson }
234c66b4d8dSRobert Watson 
235c66b4d8dSRobert Watson void
mac_socket_create(struct ucred * cred,struct socket * so)23630d239bcSRobert Watson mac_socket_create(struct ucred *cred, struct socket *so)
237c66b4d8dSRobert Watson {
238c66b4d8dSRobert Watson 
239fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label);
240c66b4d8dSRobert Watson }
241c66b4d8dSRobert Watson 
242c66b4d8dSRobert Watson void
mac_socket_newconn(struct socket * oldso,struct socket * newso)24330d239bcSRobert Watson mac_socket_newconn(struct socket *oldso, struct socket *newso)
244c66b4d8dSRobert Watson {
245c66b4d8dSRobert Watson 
246fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label,
247fa765671SRobert Watson 	    newso, newso->so_label);
248c66b4d8dSRobert Watson }
249c66b4d8dSRobert Watson 
250c66b4d8dSRobert Watson static void
mac_socket_relabel(struct ucred * cred,struct socket * so,struct label * newlabel)25130d239bcSRobert Watson mac_socket_relabel(struct ucred *cred, struct socket *so,
252c66b4d8dSRobert Watson     struct label *newlabel)
253c66b4d8dSRobert Watson {
254c66b4d8dSRobert Watson 
25526ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
25626ae2b86SRobert Watson 
257fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_relabel, cred, so, so->so_label,
25840202729SRobert Watson 	    newlabel);
259c66b4d8dSRobert Watson }
260c66b4d8dSRobert Watson 
261c66b4d8dSRobert Watson void
mac_socketpeer_set_from_mbuf(struct mbuf * m,struct socket * so)26230d239bcSRobert Watson mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
263c66b4d8dSRobert Watson {
264c66b4d8dSRobert Watson 	struct label *label;
265c66b4d8dSRobert Watson 
2663de40469SRobert Watson 	if (mac_policy_count == 0)
2673de40469SRobert Watson 		return;
2683de40469SRobert Watson 
26926ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
270c66b4d8dSRobert Watson 
271fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so,
27226ae2b86SRobert Watson 	    so->so_peerlabel);
273c66b4d8dSRobert Watson }
274c66b4d8dSRobert Watson 
275c66b4d8dSRobert Watson void
mac_socketpeer_set_from_socket(struct socket * oldso,struct socket * newso)27630d239bcSRobert Watson mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
277c66b4d8dSRobert Watson {
278c66b4d8dSRobert Watson 
279f93bfb23SRobert Watson 	if (mac_policy_count == 0)
280f93bfb23SRobert Watson 		return;
281f93bfb23SRobert Watson 
282fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso,
28340202729SRobert Watson 	    oldso->so_label, newso, newso->so_peerlabel);
284c66b4d8dSRobert Watson }
285c66b4d8dSRobert Watson 
286c66b4d8dSRobert Watson void
mac_socket_create_mbuf(struct socket * so,struct mbuf * m)28730d239bcSRobert Watson mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
288c66b4d8dSRobert Watson {
289c66b4d8dSRobert Watson 	struct label *label;
290c66b4d8dSRobert Watson 
291f93bfb23SRobert Watson 	if (mac_policy_count == 0)
292f93bfb23SRobert Watson 		return;
293c66b4d8dSRobert Watson 
29426ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
29526ae2b86SRobert Watson 
296fa765671SRobert Watson 	MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m,
297fa765671SRobert Watson 	    label);
298c66b4d8dSRobert Watson }
299c66b4d8dSRobert Watson 
3002087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *",
3012087a58cSRobert Watson     "struct socket *");
3022087a58cSRobert Watson 
303c66b4d8dSRobert Watson int
mac_socket_check_accept(struct ucred * cred,struct socket * so)30430d239bcSRobert Watson mac_socket_check_accept(struct ucred *cred, struct socket *so)
3057f53207bSRobert Watson {
3067f53207bSRobert Watson 	int error;
3077f53207bSRobert Watson 
308fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so,
309fa765671SRobert Watson 	    so->so_label);
3102087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_accept, error, cred, so);
3117f53207bSRobert Watson 
3127f53207bSRobert Watson 	return (error);
3137f53207bSRobert Watson }
3147f53207bSRobert Watson 
3152087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *",
3162087a58cSRobert Watson     "struct socket *", "struct sockaddr *");
3172087a58cSRobert Watson 
3187f53207bSRobert Watson int
mac_socket_check_bind(struct ucred * cred,struct socket * so,struct sockaddr * sa)319c14172e3SRobert Watson mac_socket_check_bind(struct ucred *cred, struct socket *so,
32026ae2b86SRobert Watson     struct sockaddr *sa)
321c66b4d8dSRobert Watson {
322c66b4d8dSRobert Watson 	int error;
323c66b4d8dSRobert Watson 
324fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label,
325fa765671SRobert Watson 	    sa);
326c14172e3SRobert Watson 	MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa);
327c66b4d8dSRobert Watson 
328c66b4d8dSRobert Watson 	return (error);
329c66b4d8dSRobert Watson }
330c66b4d8dSRobert Watson 
3312087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *",
3322087a58cSRobert Watson     "struct socket *", "struct sockaddr *");
3332087a58cSRobert Watson 
334c66b4d8dSRobert Watson int
mac_socket_check_connect(struct ucred * cred,struct socket * so,struct sockaddr * sa)33530d239bcSRobert Watson mac_socket_check_connect(struct ucred *cred, struct socket *so,
33626ae2b86SRobert Watson     struct sockaddr *sa)
337c66b4d8dSRobert Watson {
338c66b4d8dSRobert Watson 	int error;
339c66b4d8dSRobert Watson 
340fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so,
341fa765671SRobert Watson 	    so->so_label, sa);
3422087a58cSRobert Watson 	MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa);
343c66b4d8dSRobert Watson 
344c66b4d8dSRobert Watson 	return (error);
345c66b4d8dSRobert Watson }
346c66b4d8dSRobert Watson 
3472087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int",
3482087a58cSRobert Watson     "int");
3492087a58cSRobert Watson 
350c66b4d8dSRobert Watson int
mac_socket_check_create(struct ucred * cred,int domain,int type,int proto)35130d239bcSRobert Watson mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
3526758f88eSRobert Watson {
3536758f88eSRobert Watson 	int error;
3546758f88eSRobert Watson 
355fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_create, cred, domain, type,
356fa765671SRobert Watson 	    proto);
3572087a58cSRobert Watson 	MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type,
3582087a58cSRobert Watson 	    proto);
3596758f88eSRobert Watson 
3606758f88eSRobert Watson 	return (error);
3616758f88eSRobert Watson }
3626758f88eSRobert Watson 
3632087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *",
3642087a58cSRobert Watson     "struct mbuf *");
3652087a58cSRobert Watson 
3666758f88eSRobert Watson int
mac_socket_check_deliver(struct socket * so,struct mbuf * m)36730d239bcSRobert Watson mac_socket_check_deliver(struct socket *so, struct mbuf *m)
368c66b4d8dSRobert Watson {
369c66b4d8dSRobert Watson 	struct label *label;
370c66b4d8dSRobert Watson 	int error;
371c66b4d8dSRobert Watson 
372f93bfb23SRobert Watson 	if (mac_policy_count == 0)
373f93bfb23SRobert Watson 		return (0);
374310e7cebSRobert Watson 
37526ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
376c66b4d8dSRobert Watson 
377fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m,
378fa765671SRobert Watson 	    label);
3792087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_deliver, error, so, m);
380c66b4d8dSRobert Watson 
381c66b4d8dSRobert Watson 	return (error);
382c66b4d8dSRobert Watson }
383c66b4d8dSRobert Watson 
3842087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *",
3852087a58cSRobert Watson     "struct socket *");
3862087a58cSRobert Watson 
387c66b4d8dSRobert Watson int
mac_socket_check_listen(struct ucred * cred,struct socket * so)38830d239bcSRobert Watson mac_socket_check_listen(struct ucred *cred, struct socket *so)
389c66b4d8dSRobert Watson {
390c66b4d8dSRobert Watson 	int error;
391c66b4d8dSRobert Watson 
392fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so,
393fa765671SRobert Watson 	    so->so_label);
3942087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_listen, error, cred, so);
39526ae2b86SRobert Watson 
396c66b4d8dSRobert Watson 	return (error);
397c66b4d8dSRobert Watson }
398c66b4d8dSRobert Watson 
3992087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *",
4002087a58cSRobert Watson     "struct socket *");
4012087a58cSRobert Watson 
402c66b4d8dSRobert Watson int
mac_socket_check_poll(struct ucred * cred,struct socket * so)40330d239bcSRobert Watson mac_socket_check_poll(struct ucred *cred, struct socket *so)
4047f53207bSRobert Watson {
4057f53207bSRobert Watson 	int error;
4067f53207bSRobert Watson 
407fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label);
4082087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_poll, error, cred, so);
40926ae2b86SRobert Watson 
4107f53207bSRobert Watson 	return (error);
4117f53207bSRobert Watson }
4127f53207bSRobert Watson 
4132087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *",
4142087a58cSRobert Watson     "struct socket *");
4152087a58cSRobert Watson 
4167f53207bSRobert Watson int
mac_socket_check_receive(struct ucred * cred,struct socket * so)41730d239bcSRobert Watson mac_socket_check_receive(struct ucred *cred, struct socket *so)
418c66b4d8dSRobert Watson {
419c66b4d8dSRobert Watson 	int error;
420c66b4d8dSRobert Watson 
421fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so,
422fa765671SRobert Watson 	    so->so_label);
4232087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_receive, error, cred, so);
424c66b4d8dSRobert Watson 
425c66b4d8dSRobert Watson 	return (error);
426c66b4d8dSRobert Watson }
427c66b4d8dSRobert Watson 
4282087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *",
4292087a58cSRobert Watson     "struct socket *", "struct label *");
4302087a58cSRobert Watson 
431c66b4d8dSRobert Watson static int
mac_socket_check_relabel(struct ucred * cred,struct socket * so,struct label * newlabel)43230d239bcSRobert Watson mac_socket_check_relabel(struct ucred *cred, struct socket *so,
433c66b4d8dSRobert Watson     struct label *newlabel)
434c66b4d8dSRobert Watson {
435c66b4d8dSRobert Watson 	int error;
436c66b4d8dSRobert Watson 
43726ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
438310e7cebSRobert Watson 
439fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_relabel, cred, so,
440fa765671SRobert Watson 	    so->so_label, newlabel);
4412087a58cSRobert Watson 	MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel);
442c66b4d8dSRobert Watson 
443c66b4d8dSRobert Watson 	return (error);
444c66b4d8dSRobert Watson }
445c66b4d8dSRobert Watson 
4462087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *",
4472087a58cSRobert Watson     "struct socket *");
4482087a58cSRobert Watson 
449c66b4d8dSRobert Watson int
mac_socket_check_send(struct ucred * cred,struct socket * so)45030d239bcSRobert Watson mac_socket_check_send(struct ucred *cred, struct socket *so)
451c66b4d8dSRobert Watson {
452c66b4d8dSRobert Watson 	int error;
453c66b4d8dSRobert Watson 
454fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label);
4552087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_send, error, cred, so);
456c66b4d8dSRobert Watson 
457c66b4d8dSRobert Watson 	return (error);
458c66b4d8dSRobert Watson }
459c66b4d8dSRobert Watson 
4602087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *",
4612087a58cSRobert Watson     "struct socket *");
4622087a58cSRobert Watson 
463c66b4d8dSRobert Watson int
mac_socket_check_stat(struct ucred * cred,struct socket * so)46430d239bcSRobert Watson mac_socket_check_stat(struct ucred *cred, struct socket *so)
4657f53207bSRobert Watson {
4667f53207bSRobert Watson 	int error;
4677f53207bSRobert Watson 
468fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label);
4692087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_stat, error, cred, so);
4707f53207bSRobert Watson 
4717f53207bSRobert Watson 	return (error);
4727f53207bSRobert Watson }
4737f53207bSRobert Watson 
4742087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *",
4752087a58cSRobert Watson     "struct socket *");
4762087a58cSRobert Watson 
4777f53207bSRobert Watson int
mac_socket_check_visible(struct ucred * cred,struct socket * so)47830d239bcSRobert Watson mac_socket_check_visible(struct ucred *cred, struct socket *so)
479c66b4d8dSRobert Watson {
480c66b4d8dSRobert Watson 	int error;
481c66b4d8dSRobert Watson 
482fa765671SRobert Watson 	MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so,
483fa765671SRobert Watson 	    so->so_label);
4842087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_visible, error, cred, so);
485c66b4d8dSRobert Watson 
486c66b4d8dSRobert Watson 	return (error);
487c66b4d8dSRobert Watson }
488c66b4d8dSRobert Watson 
489c66b4d8dSRobert Watson int
mac_socket_label_set(struct ucred * cred,struct socket * so,struct label * label)490c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so,
491c66b4d8dSRobert Watson     struct label *label)
492c66b4d8dSRobert Watson {
493c66b4d8dSRobert Watson 	int error;
494c66b4d8dSRobert Watson 
495310e7cebSRobert Watson 	/*
496df3c68e4SRobert Watson 	 * We acquire the socket lock when we perform the test and set, but
497df3c68e4SRobert Watson 	 * have to release it as the pcb code needs to acquire the pcb lock,
498df3c68e4SRobert Watson 	 * which will precede the socket lock in the lock order.  However,
499df3c68e4SRobert Watson 	 * this is fine, as any race will simply result in the inpcb being
500df3c68e4SRobert Watson 	 * refreshed twice, but still consistently, as the inpcb code will
501df3c68e4SRobert Watson 	 * acquire the socket lock before refreshing, holding both locks.
502310e7cebSRobert Watson 	 */
503310e7cebSRobert Watson 	SOCK_LOCK(so);
50430d239bcSRobert Watson 	error = mac_socket_check_relabel(cred, so, label);
505310e7cebSRobert Watson 	if (error) {
506310e7cebSRobert Watson 		SOCK_UNLOCK(so);
507c66b4d8dSRobert Watson 		return (error);
508310e7cebSRobert Watson 	}
509c66b4d8dSRobert Watson 
51030d239bcSRobert Watson 	mac_socket_relabel(cred, so, label);
511310e7cebSRobert Watson 	SOCK_UNLOCK(so);
512df3c68e4SRobert Watson 
513c66b4d8dSRobert Watson 	/*
514c66b4d8dSRobert Watson 	 * If the protocol has expressed interest in socket layer changes,
515df3c68e4SRobert Watson 	 * such as if it needs to propagate changes to a cached pcb label
516df3c68e4SRobert Watson 	 * from the socket, notify it of the label change while holding the
517df3c68e4SRobert Watson 	 * socket lock.
518c66b4d8dSRobert Watson 	 */
519e7d02be1SGleb Smirnoff 	if (so->so_proto->pr_sosetlabel != NULL)
520e7d02be1SGleb Smirnoff 		so->so_proto->pr_sosetlabel(so);
521c66b4d8dSRobert Watson 
522c66b4d8dSRobert Watson 	return (0);
523c66b4d8dSRobert Watson }
524c66b4d8dSRobert Watson 
525c66b4d8dSRobert Watson int
mac_setsockopt_label(struct ucred * cred,struct socket * so,const struct mac * mac)526f64a688dSBrooks Davis mac_setsockopt_label(struct ucred *cred, struct socket *so,
527f64a688dSBrooks Davis     const struct mac *mac)
528c66b4d8dSRobert Watson {
529c66b4d8dSRobert Watson 	struct label *intlabel;
530c66b4d8dSRobert Watson 	char *buffer;
531c66b4d8dSRobert Watson 	int error;
532c66b4d8dSRobert Watson 
5336356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
5346356dba0SRobert Watson 		return (EINVAL);
5356356dba0SRobert Watson 
536c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
537c66b4d8dSRobert Watson 	if (error)
538c66b4d8dSRobert Watson 		return (error);
539c66b4d8dSRobert Watson 
540c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
541c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
542c66b4d8dSRobert Watson 	if (error) {
543c66b4d8dSRobert Watson 		free(buffer, M_MACTEMP);
544c66b4d8dSRobert Watson 		return (error);
545c66b4d8dSRobert Watson 	}
546c66b4d8dSRobert Watson 
547c66b4d8dSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
54830d239bcSRobert Watson 	error = mac_socket_internalize_label(intlabel, buffer);
549c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
550c66b4d8dSRobert Watson 	if (error)
551c66b4d8dSRobert Watson 		goto out;
552c66b4d8dSRobert Watson 
553c66b4d8dSRobert Watson 	error = mac_socket_label_set(cred, so, intlabel);
554c66b4d8dSRobert Watson out:
555c66b4d8dSRobert Watson 	mac_socket_label_free(intlabel);
556c66b4d8dSRobert Watson 	return (error);
557c66b4d8dSRobert Watson }
558c66b4d8dSRobert Watson 
559c66b4d8dSRobert Watson int
mac_getsockopt_label(struct ucred * cred,struct socket * so,const struct mac * mac)560f64a688dSBrooks Davis mac_getsockopt_label(struct ucred *cred, struct socket *so,
561f64a688dSBrooks Davis     const struct mac *mac)
562c66b4d8dSRobert Watson {
563c66b4d8dSRobert Watson 	char *buffer, *elements;
564310e7cebSRobert Watson 	struct label *intlabel;
565c66b4d8dSRobert Watson 	int error;
566c66b4d8dSRobert Watson 
5676356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
5686356dba0SRobert Watson 		return (EINVAL);
5696356dba0SRobert Watson 
570c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
571c66b4d8dSRobert Watson 	if (error)
572c66b4d8dSRobert Watson 		return (error);
573c66b4d8dSRobert Watson 
574c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
575c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
576c66b4d8dSRobert Watson 	if (error) {
577c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
578c66b4d8dSRobert Watson 		return (error);
579c66b4d8dSRobert Watson 	}
580c66b4d8dSRobert Watson 
581c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
582310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
583310e7cebSRobert Watson 	SOCK_LOCK(so);
58430d239bcSRobert Watson 	mac_socket_copy_label(so->so_label, intlabel);
585310e7cebSRobert Watson 	SOCK_UNLOCK(so);
58630d239bcSRobert Watson 	error = mac_socket_externalize_label(intlabel, elements, buffer,
587310e7cebSRobert Watson 	    mac->m_buflen);
588310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
589c66b4d8dSRobert Watson 	if (error == 0)
590c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
591c66b4d8dSRobert Watson 
592c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
593c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
594c66b4d8dSRobert Watson 
595c66b4d8dSRobert Watson 	return (error);
596c66b4d8dSRobert Watson }
597c66b4d8dSRobert Watson 
598c66b4d8dSRobert Watson int
mac_getsockopt_peerlabel(struct ucred * cred,struct socket * so,const struct mac * mac)599c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
600f64a688dSBrooks Davis     const struct mac *mac)
601c66b4d8dSRobert Watson {
602c66b4d8dSRobert Watson 	char *elements, *buffer;
603310e7cebSRobert Watson 	struct label *intlabel;
604c66b4d8dSRobert Watson 	int error;
605c66b4d8dSRobert Watson 
6066356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
6076356dba0SRobert Watson 		return (EINVAL);
6086356dba0SRobert Watson 
609c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
610c66b4d8dSRobert Watson 	if (error)
611c66b4d8dSRobert Watson 		return (error);
612c66b4d8dSRobert Watson 
613c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
614c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
615c66b4d8dSRobert Watson 	if (error) {
616c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
617c66b4d8dSRobert Watson 		return (error);
618c66b4d8dSRobert Watson 	}
619c66b4d8dSRobert Watson 
620c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
621310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
622310e7cebSRobert Watson 	SOCK_LOCK(so);
623*2fb778faSMichael Tuexen 	if (SOLISTENING(so))
624*2fb778faSMichael Tuexen 		error = EINVAL;
625*2fb778faSMichael Tuexen 	else
62630d239bcSRobert Watson 		mac_socket_copy_label(so->so_peerlabel, intlabel);
627310e7cebSRobert Watson 	SOCK_UNLOCK(so);
628*2fb778faSMichael Tuexen 	if (error == 0) {
62930d239bcSRobert Watson 		error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
630310e7cebSRobert Watson 		    mac->m_buflen);
631*2fb778faSMichael Tuexen 	}
632310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
633c66b4d8dSRobert Watson 	if (error == 0)
634c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
635c66b4d8dSRobert Watson 
636c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
637c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
638c66b4d8dSRobert Watson 
639c66b4d8dSRobert Watson 	return (error);
640c66b4d8dSRobert Watson }
641