xref: /f-stack/freebsd/security/mac/mac_socket.c (revision 22ce4aff)
1*a9643ea8Slogwang /*-
2*a9643ea8Slogwang  * Copyright (c) 1999-2002, 2009 Robert N. M. Watson
3*a9643ea8Slogwang  * Copyright (c) 2001 Ilmar S. Habibulin
4*a9643ea8Slogwang  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5*a9643ea8Slogwang  * Copyright (c) 2005-2006 SPARTA, Inc.
6*a9643ea8Slogwang  * Copyright (c) 2008 Apple Inc.
7*a9643ea8Slogwang  * All rights reserved.
8*a9643ea8Slogwang  *
9*a9643ea8Slogwang  * This software was developed by Robert Watson and Ilmar Habibulin for the
10*a9643ea8Slogwang  * TrustedBSD Project.
11*a9643ea8Slogwang  *
12*a9643ea8Slogwang  * This software was developed for the FreeBSD Project in part by McAfee
13*a9643ea8Slogwang  * Research, the Technology Research Division of Network Associates, Inc.
14*a9643ea8Slogwang  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
15*a9643ea8Slogwang  * DARPA CHATS research program.
16*a9643ea8Slogwang  *
17*a9643ea8Slogwang  * This software was enhanced by SPARTA ISSO under SPAWAR contract
18*a9643ea8Slogwang  * N66001-04-C-6019 ("SEFOS").
19*a9643ea8Slogwang  *
20*a9643ea8Slogwang  * This software was developed at the University of Cambridge Computer
21*a9643ea8Slogwang  * Laboratory with support from a grant from Google, Inc.
22*a9643ea8Slogwang  *
23*a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or without
24*a9643ea8Slogwang  * modification, are permitted provided that the following conditions
25*a9643ea8Slogwang  * are met:
26*a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
27*a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer.
28*a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
29*a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer in the
30*a9643ea8Slogwang  *    documentation and/or other materials provided with the distribution.
31*a9643ea8Slogwang  *
32*a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33*a9643ea8Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34*a9643ea8Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35*a9643ea8Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36*a9643ea8Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37*a9643ea8Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38*a9643ea8Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39*a9643ea8Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40*a9643ea8Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41*a9643ea8Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42*a9643ea8Slogwang  * SUCH DAMAGE.
43*a9643ea8Slogwang  */
44*a9643ea8Slogwang 
45*a9643ea8Slogwang #include <sys/cdefs.h>
46*a9643ea8Slogwang __FBSDID("$FreeBSD$");
47*a9643ea8Slogwang 
48*a9643ea8Slogwang #include "opt_mac.h"
49*a9643ea8Slogwang 
50*a9643ea8Slogwang #include <sys/param.h>
51*a9643ea8Slogwang #include <sys/kernel.h>
52*a9643ea8Slogwang #include <sys/lock.h>
53*a9643ea8Slogwang #include <sys/malloc.h>
54*a9643ea8Slogwang #include <sys/mutex.h>
55*a9643ea8Slogwang #include <sys/mac.h>
56*a9643ea8Slogwang #include <sys/sbuf.h>
57*a9643ea8Slogwang #include <sys/sdt.h>
58*a9643ea8Slogwang #include <sys/systm.h>
59*a9643ea8Slogwang #include <sys/mount.h>
60*a9643ea8Slogwang #include <sys/file.h>
61*a9643ea8Slogwang #include <sys/namei.h>
62*a9643ea8Slogwang #include <sys/protosw.h>
63*a9643ea8Slogwang #include <sys/socket.h>
64*a9643ea8Slogwang #include <sys/socketvar.h>
65*a9643ea8Slogwang #include <sys/sysctl.h>
66*a9643ea8Slogwang 
67*a9643ea8Slogwang #include <net/bpfdesc.h>
68*a9643ea8Slogwang #include <net/if.h>
69*a9643ea8Slogwang #include <net/if_var.h>
70*a9643ea8Slogwang 
71*a9643ea8Slogwang #include <netinet/in.h>
72*a9643ea8Slogwang #include <netinet/in_pcb.h>
73*a9643ea8Slogwang #include <netinet/ip_var.h>
74*a9643ea8Slogwang 
75*a9643ea8Slogwang #include <security/mac/mac_framework.h>
76*a9643ea8Slogwang #include <security/mac/mac_internal.h>
77*a9643ea8Slogwang #include <security/mac/mac_policy.h>
78*a9643ea8Slogwang 
79*a9643ea8Slogwang /*
80*a9643ea8Slogwang  * Currently, sockets hold two labels: the label of the socket itself, and a
81*a9643ea8Slogwang  * peer label, which may be used by policies to hold a copy of the label of
82*a9643ea8Slogwang  * any remote endpoint.
83*a9643ea8Slogwang  *
84*a9643ea8Slogwang  * Possibly, this peer label should be maintained at the protocol layer
85*a9643ea8Slogwang  * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
86*a9643ea8Slogwang  * the label consistently.  For example, it might be copied live from a
87*a9643ea8Slogwang  * remote socket for UNIX domain sockets rather than keeping a local copy on
88*a9643ea8Slogwang  * this endpoint, but be cached and updated based on packets received for
89*a9643ea8Slogwang  * TCP/IP.
90*a9643ea8Slogwang  *
91*a9643ea8Slogwang  * Unlike with many other object types, the lock protecting MAC labels on
92*a9643ea8Slogwang  * sockets (the socket lock) is not frequently held at the points in code
93*a9643ea8Slogwang  * where socket-related checks are called.  The MAC Framework acquires the
94*a9643ea8Slogwang  * lock over some entry points in order to enforce atomicity (such as label
95*a9643ea8Slogwang  * copies) but in other cases the policy modules will have to acquire the
96*a9643ea8Slogwang  * lock themselves if they use labels.  This approach (a) avoids lock
97*a9643ea8Slogwang  * acquisitions when policies don't require labels and (b) solves a number of
98*a9643ea8Slogwang  * potential lock order issues when multiple sockets are used in the same
99*a9643ea8Slogwang  * entry point.
100*a9643ea8Slogwang  */
101*a9643ea8Slogwang 
102*a9643ea8Slogwang struct label *
mac_socket_label_alloc(int flag)103*a9643ea8Slogwang mac_socket_label_alloc(int flag)
104*a9643ea8Slogwang {
105*a9643ea8Slogwang 	struct label *label;
106*a9643ea8Slogwang 	int error;
107*a9643ea8Slogwang 
108*a9643ea8Slogwang 	label = mac_labelzone_alloc(flag);
109*a9643ea8Slogwang 	if (label == NULL)
110*a9643ea8Slogwang 		return (NULL);
111*a9643ea8Slogwang 
112*a9643ea8Slogwang 	if (flag & M_WAITOK)
113*a9643ea8Slogwang 		MAC_POLICY_CHECK(socket_init_label, label, flag);
114*a9643ea8Slogwang 	else
115*a9643ea8Slogwang 		MAC_POLICY_CHECK_NOSLEEP(socket_init_label, label, flag);
116*a9643ea8Slogwang 	if (error) {
117*a9643ea8Slogwang 		MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
118*a9643ea8Slogwang 		mac_labelzone_free(label);
119*a9643ea8Slogwang 		return (NULL);
120*a9643ea8Slogwang 	}
121*a9643ea8Slogwang 	return (label);
122*a9643ea8Slogwang }
123*a9643ea8Slogwang 
124*a9643ea8Slogwang static struct label *
mac_socketpeer_label_alloc(int flag)125*a9643ea8Slogwang mac_socketpeer_label_alloc(int flag)
126*a9643ea8Slogwang {
127*a9643ea8Slogwang 	struct label *label;
128*a9643ea8Slogwang 	int error;
129*a9643ea8Slogwang 
130*a9643ea8Slogwang 	label = mac_labelzone_alloc(flag);
131*a9643ea8Slogwang 	if (label == NULL)
132*a9643ea8Slogwang 		return (NULL);
133*a9643ea8Slogwang 
134*a9643ea8Slogwang 	if (flag & M_WAITOK)
135*a9643ea8Slogwang 		MAC_POLICY_CHECK(socketpeer_init_label, label, flag);
136*a9643ea8Slogwang 	else
137*a9643ea8Slogwang 		MAC_POLICY_CHECK_NOSLEEP(socketpeer_init_label, label, flag);
138*a9643ea8Slogwang 	if (error) {
139*a9643ea8Slogwang 		MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
140*a9643ea8Slogwang 		mac_labelzone_free(label);
141*a9643ea8Slogwang 		return (NULL);
142*a9643ea8Slogwang 	}
143*a9643ea8Slogwang 	return (label);
144*a9643ea8Slogwang }
145*a9643ea8Slogwang 
146*a9643ea8Slogwang int
mac_socket_init(struct socket * so,int flag)147*a9643ea8Slogwang mac_socket_init(struct socket *so, int flag)
148*a9643ea8Slogwang {
149*a9643ea8Slogwang 
150*a9643ea8Slogwang 	if (mac_labeled & MPC_OBJECT_SOCKET) {
151*a9643ea8Slogwang 		so->so_label = mac_socket_label_alloc(flag);
152*a9643ea8Slogwang 		if (so->so_label == NULL)
153*a9643ea8Slogwang 			return (ENOMEM);
154*a9643ea8Slogwang 		so->so_peerlabel = mac_socketpeer_label_alloc(flag);
155*a9643ea8Slogwang 		if (so->so_peerlabel == NULL) {
156*a9643ea8Slogwang 			mac_socket_label_free(so->so_label);
157*a9643ea8Slogwang 			so->so_label = NULL;
158*a9643ea8Slogwang 			return (ENOMEM);
159*a9643ea8Slogwang 		}
160*a9643ea8Slogwang 	} else {
161*a9643ea8Slogwang 		so->so_label = NULL;
162*a9643ea8Slogwang 		so->so_peerlabel = NULL;
163*a9643ea8Slogwang 	}
164*a9643ea8Slogwang 	return (0);
165*a9643ea8Slogwang }
166*a9643ea8Slogwang 
167*a9643ea8Slogwang void
mac_socket_label_free(struct label * label)168*a9643ea8Slogwang mac_socket_label_free(struct label *label)
169*a9643ea8Slogwang {
170*a9643ea8Slogwang 
171*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
172*a9643ea8Slogwang 	mac_labelzone_free(label);
173*a9643ea8Slogwang }
174*a9643ea8Slogwang 
175*a9643ea8Slogwang static void
mac_socketpeer_label_free(struct label * label)176*a9643ea8Slogwang mac_socketpeer_label_free(struct label *label)
177*a9643ea8Slogwang {
178*a9643ea8Slogwang 
179*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
180*a9643ea8Slogwang 	mac_labelzone_free(label);
181*a9643ea8Slogwang }
182*a9643ea8Slogwang 
183*a9643ea8Slogwang void
mac_socket_destroy(struct socket * so)184*a9643ea8Slogwang mac_socket_destroy(struct socket *so)
185*a9643ea8Slogwang {
186*a9643ea8Slogwang 
187*a9643ea8Slogwang 	if (so->so_label != NULL) {
188*a9643ea8Slogwang 		mac_socket_label_free(so->so_label);
189*a9643ea8Slogwang 		so->so_label = NULL;
190*a9643ea8Slogwang 		mac_socketpeer_label_free(so->so_peerlabel);
191*a9643ea8Slogwang 		so->so_peerlabel = NULL;
192*a9643ea8Slogwang 	}
193*a9643ea8Slogwang }
194*a9643ea8Slogwang 
195*a9643ea8Slogwang void
mac_socket_copy_label(struct label * src,struct label * dest)196*a9643ea8Slogwang mac_socket_copy_label(struct label *src, struct label *dest)
197*a9643ea8Slogwang {
198*a9643ea8Slogwang 
199*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest);
200*a9643ea8Slogwang }
201*a9643ea8Slogwang 
202*a9643ea8Slogwang int
mac_socket_externalize_label(struct label * label,char * elements,char * outbuf,size_t outbuflen)203*a9643ea8Slogwang mac_socket_externalize_label(struct label *label, char *elements,
204*a9643ea8Slogwang     char *outbuf, size_t outbuflen)
205*a9643ea8Slogwang {
206*a9643ea8Slogwang 	int error;
207*a9643ea8Slogwang 
208*a9643ea8Slogwang 	MAC_POLICY_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
209*a9643ea8Slogwang 
210*a9643ea8Slogwang 	return (error);
211*a9643ea8Slogwang }
212*a9643ea8Slogwang 
213*a9643ea8Slogwang static int
mac_socketpeer_externalize_label(struct label * label,char * elements,char * outbuf,size_t outbuflen)214*a9643ea8Slogwang mac_socketpeer_externalize_label(struct label *label, char *elements,
215*a9643ea8Slogwang     char *outbuf, size_t outbuflen)
216*a9643ea8Slogwang {
217*a9643ea8Slogwang 	int error;
218*a9643ea8Slogwang 
219*a9643ea8Slogwang 	MAC_POLICY_EXTERNALIZE(socketpeer, label, elements, outbuf,
220*a9643ea8Slogwang 	    outbuflen);
221*a9643ea8Slogwang 
222*a9643ea8Slogwang 	return (error);
223*a9643ea8Slogwang }
224*a9643ea8Slogwang 
225*a9643ea8Slogwang int
mac_socket_internalize_label(struct label * label,char * string)226*a9643ea8Slogwang mac_socket_internalize_label(struct label *label, char *string)
227*a9643ea8Slogwang {
228*a9643ea8Slogwang 	int error;
229*a9643ea8Slogwang 
230*a9643ea8Slogwang 	MAC_POLICY_INTERNALIZE(socket, label, string);
231*a9643ea8Slogwang 
232*a9643ea8Slogwang 	return (error);
233*a9643ea8Slogwang }
234*a9643ea8Slogwang 
235*a9643ea8Slogwang void
mac_socket_create(struct ucred * cred,struct socket * so)236*a9643ea8Slogwang mac_socket_create(struct ucred *cred, struct socket *so)
237*a9643ea8Slogwang {
238*a9643ea8Slogwang 
239*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label);
240*a9643ea8Slogwang }
241*a9643ea8Slogwang 
242*a9643ea8Slogwang void
mac_socket_newconn(struct socket * oldso,struct socket * newso)243*a9643ea8Slogwang mac_socket_newconn(struct socket *oldso, struct socket *newso)
244*a9643ea8Slogwang {
245*a9643ea8Slogwang 
246*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label,
247*a9643ea8Slogwang 	    newso, newso->so_label);
248*a9643ea8Slogwang }
249*a9643ea8Slogwang 
250*a9643ea8Slogwang static void
mac_socket_relabel(struct ucred * cred,struct socket * so,struct label * newlabel)251*a9643ea8Slogwang mac_socket_relabel(struct ucred *cred, struct socket *so,
252*a9643ea8Slogwang     struct label *newlabel)
253*a9643ea8Slogwang {
254*a9643ea8Slogwang 
255*a9643ea8Slogwang 	SOCK_LOCK_ASSERT(so);
256*a9643ea8Slogwang 
257*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socket_relabel, cred, so, so->so_label,
258*a9643ea8Slogwang 	    newlabel);
259*a9643ea8Slogwang }
260*a9643ea8Slogwang 
261*a9643ea8Slogwang void
mac_socketpeer_set_from_mbuf(struct mbuf * m,struct socket * so)262*a9643ea8Slogwang mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
263*a9643ea8Slogwang {
264*a9643ea8Slogwang 	struct label *label;
265*a9643ea8Slogwang 
266*a9643ea8Slogwang 	if (mac_policy_count == 0)
267*a9643ea8Slogwang 		return;
268*a9643ea8Slogwang 
269*a9643ea8Slogwang 	label = mac_mbuf_to_label(m);
270*a9643ea8Slogwang 
271*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so,
272*a9643ea8Slogwang 	    so->so_peerlabel);
273*a9643ea8Slogwang }
274*a9643ea8Slogwang 
275*a9643ea8Slogwang void
mac_socketpeer_set_from_socket(struct socket * oldso,struct socket * newso)276*a9643ea8Slogwang mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
277*a9643ea8Slogwang {
278*a9643ea8Slogwang 
279*a9643ea8Slogwang 	if (mac_policy_count == 0)
280*a9643ea8Slogwang 		return;
281*a9643ea8Slogwang 
282*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso,
283*a9643ea8Slogwang 	    oldso->so_label, newso, newso->so_peerlabel);
284*a9643ea8Slogwang }
285*a9643ea8Slogwang 
286*a9643ea8Slogwang void
mac_socket_create_mbuf(struct socket * so,struct mbuf * m)287*a9643ea8Slogwang mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
288*a9643ea8Slogwang {
289*a9643ea8Slogwang 	struct label *label;
290*a9643ea8Slogwang 
291*a9643ea8Slogwang 	if (mac_policy_count == 0)
292*a9643ea8Slogwang 		return;
293*a9643ea8Slogwang 
294*a9643ea8Slogwang 	label = mac_mbuf_to_label(m);
295*a9643ea8Slogwang 
296*a9643ea8Slogwang 	MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m,
297*a9643ea8Slogwang 	    label);
298*a9643ea8Slogwang }
299*a9643ea8Slogwang 
300*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *",
301*a9643ea8Slogwang     "struct socket *");
302*a9643ea8Slogwang 
303*a9643ea8Slogwang int
mac_socket_check_accept(struct ucred * cred,struct socket * so)304*a9643ea8Slogwang mac_socket_check_accept(struct ucred *cred, struct socket *so)
305*a9643ea8Slogwang {
306*a9643ea8Slogwang 	int error;
307*a9643ea8Slogwang 
308*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so,
309*a9643ea8Slogwang 	    so->so_label);
310*a9643ea8Slogwang 	MAC_CHECK_PROBE2(socket_check_accept, error, cred, so);
311*a9643ea8Slogwang 
312*a9643ea8Slogwang 	return (error);
313*a9643ea8Slogwang }
314*a9643ea8Slogwang 
315*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *",
316*a9643ea8Slogwang     "struct socket *", "struct sockaddr *");
317*a9643ea8Slogwang 
318*a9643ea8Slogwang int
mac_socket_check_bind(struct ucred * cred,struct socket * so,struct sockaddr * sa)319*a9643ea8Slogwang mac_socket_check_bind(struct ucred *cred, struct socket *so,
320*a9643ea8Slogwang     struct sockaddr *sa)
321*a9643ea8Slogwang {
322*a9643ea8Slogwang 	int error;
323*a9643ea8Slogwang 
324*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label,
325*a9643ea8Slogwang 	    sa);
326*a9643ea8Slogwang 	MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa);
327*a9643ea8Slogwang 
328*a9643ea8Slogwang 	return (error);
329*a9643ea8Slogwang }
330*a9643ea8Slogwang 
331*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *",
332*a9643ea8Slogwang     "struct socket *", "struct sockaddr *");
333*a9643ea8Slogwang 
334*a9643ea8Slogwang int
mac_socket_check_connect(struct ucred * cred,struct socket * so,struct sockaddr * sa)335*a9643ea8Slogwang mac_socket_check_connect(struct ucred *cred, struct socket *so,
336*a9643ea8Slogwang     struct sockaddr *sa)
337*a9643ea8Slogwang {
338*a9643ea8Slogwang 	int error;
339*a9643ea8Slogwang 
340*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so,
341*a9643ea8Slogwang 	    so->so_label, sa);
342*a9643ea8Slogwang 	MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa);
343*a9643ea8Slogwang 
344*a9643ea8Slogwang 	return (error);
345*a9643ea8Slogwang }
346*a9643ea8Slogwang 
347*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int",
348*a9643ea8Slogwang     "int");
349*a9643ea8Slogwang 
350*a9643ea8Slogwang int
mac_socket_check_create(struct ucred * cred,int domain,int type,int proto)351*a9643ea8Slogwang mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
352*a9643ea8Slogwang {
353*a9643ea8Slogwang 	int error;
354*a9643ea8Slogwang 
355*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_create, cred, domain, type,
356*a9643ea8Slogwang 	    proto);
357*a9643ea8Slogwang 	MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type,
358*a9643ea8Slogwang 	    proto);
359*a9643ea8Slogwang 
360*a9643ea8Slogwang 	return (error);
361*a9643ea8Slogwang }
362*a9643ea8Slogwang 
363*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *",
364*a9643ea8Slogwang     "struct mbuf *");
365*a9643ea8Slogwang 
366*a9643ea8Slogwang int
mac_socket_check_deliver(struct socket * so,struct mbuf * m)367*a9643ea8Slogwang mac_socket_check_deliver(struct socket *so, struct mbuf *m)
368*a9643ea8Slogwang {
369*a9643ea8Slogwang 	struct label *label;
370*a9643ea8Slogwang 	int error;
371*a9643ea8Slogwang 
372*a9643ea8Slogwang 	if (mac_policy_count == 0)
373*a9643ea8Slogwang 		return (0);
374*a9643ea8Slogwang 
375*a9643ea8Slogwang 	label = mac_mbuf_to_label(m);
376*a9643ea8Slogwang 
377*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m,
378*a9643ea8Slogwang 	    label);
379*a9643ea8Slogwang 	MAC_CHECK_PROBE2(socket_check_deliver, error, so, m);
380*a9643ea8Slogwang 
381*a9643ea8Slogwang 	return (error);
382*a9643ea8Slogwang }
383*a9643ea8Slogwang 
384*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *",
385*a9643ea8Slogwang     "struct socket *");
386*a9643ea8Slogwang 
387*a9643ea8Slogwang int
mac_socket_check_listen(struct ucred * cred,struct socket * so)388*a9643ea8Slogwang mac_socket_check_listen(struct ucred *cred, struct socket *so)
389*a9643ea8Slogwang {
390*a9643ea8Slogwang 	int error;
391*a9643ea8Slogwang 
392*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so,
393*a9643ea8Slogwang 	    so->so_label);
394*a9643ea8Slogwang 	MAC_CHECK_PROBE2(socket_check_listen, error, cred, so);
395*a9643ea8Slogwang 
396*a9643ea8Slogwang 	return (error);
397*a9643ea8Slogwang }
398*a9643ea8Slogwang 
399*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *",
400*a9643ea8Slogwang     "struct socket *");
401*a9643ea8Slogwang 
402*a9643ea8Slogwang int
mac_socket_check_poll(struct ucred * cred,struct socket * so)403*a9643ea8Slogwang mac_socket_check_poll(struct ucred *cred, struct socket *so)
404*a9643ea8Slogwang {
405*a9643ea8Slogwang 	int error;
406*a9643ea8Slogwang 
407*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label);
408*a9643ea8Slogwang 	MAC_CHECK_PROBE2(socket_check_poll, error, cred, so);
409*a9643ea8Slogwang 
410*a9643ea8Slogwang 	return (error);
411*a9643ea8Slogwang }
412*a9643ea8Slogwang 
413*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *",
414*a9643ea8Slogwang     "struct socket *");
415*a9643ea8Slogwang 
416*a9643ea8Slogwang int
mac_socket_check_receive(struct ucred * cred,struct socket * so)417*a9643ea8Slogwang mac_socket_check_receive(struct ucred *cred, struct socket *so)
418*a9643ea8Slogwang {
419*a9643ea8Slogwang 	int error;
420*a9643ea8Slogwang 
421*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so,
422*a9643ea8Slogwang 	    so->so_label);
423*a9643ea8Slogwang 	MAC_CHECK_PROBE2(socket_check_receive, error, cred, so);
424*a9643ea8Slogwang 
425*a9643ea8Slogwang 	return (error);
426*a9643ea8Slogwang }
427*a9643ea8Slogwang 
428*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *",
429*a9643ea8Slogwang     "struct socket *", "struct label *");
430*a9643ea8Slogwang 
431*a9643ea8Slogwang static int
mac_socket_check_relabel(struct ucred * cred,struct socket * so,struct label * newlabel)432*a9643ea8Slogwang mac_socket_check_relabel(struct ucred *cred, struct socket *so,
433*a9643ea8Slogwang     struct label *newlabel)
434*a9643ea8Slogwang {
435*a9643ea8Slogwang 	int error;
436*a9643ea8Slogwang 
437*a9643ea8Slogwang 	SOCK_LOCK_ASSERT(so);
438*a9643ea8Slogwang 
439*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_relabel, cred, so,
440*a9643ea8Slogwang 	    so->so_label, newlabel);
441*a9643ea8Slogwang 	MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel);
442*a9643ea8Slogwang 
443*a9643ea8Slogwang 	return (error);
444*a9643ea8Slogwang }
445*a9643ea8Slogwang 
446*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *",
447*a9643ea8Slogwang     "struct socket *");
448*a9643ea8Slogwang 
449*a9643ea8Slogwang int
mac_socket_check_send(struct ucred * cred,struct socket * so)450*a9643ea8Slogwang mac_socket_check_send(struct ucred *cred, struct socket *so)
451*a9643ea8Slogwang {
452*a9643ea8Slogwang 	int error;
453*a9643ea8Slogwang 
454*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label);
455*a9643ea8Slogwang 	MAC_CHECK_PROBE2(socket_check_send, error, cred, so);
456*a9643ea8Slogwang 
457*a9643ea8Slogwang 	return (error);
458*a9643ea8Slogwang }
459*a9643ea8Slogwang 
460*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *",
461*a9643ea8Slogwang     "struct socket *");
462*a9643ea8Slogwang 
463*a9643ea8Slogwang int
mac_socket_check_stat(struct ucred * cred,struct socket * so)464*a9643ea8Slogwang mac_socket_check_stat(struct ucred *cred, struct socket *so)
465*a9643ea8Slogwang {
466*a9643ea8Slogwang 	int error;
467*a9643ea8Slogwang 
468*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label);
469*a9643ea8Slogwang 	MAC_CHECK_PROBE2(socket_check_stat, error, cred, so);
470*a9643ea8Slogwang 
471*a9643ea8Slogwang 	return (error);
472*a9643ea8Slogwang }
473*a9643ea8Slogwang 
474*a9643ea8Slogwang MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *",
475*a9643ea8Slogwang     "struct socket *");
476*a9643ea8Slogwang 
477*a9643ea8Slogwang int
mac_socket_check_visible(struct ucred * cred,struct socket * so)478*a9643ea8Slogwang mac_socket_check_visible(struct ucred *cred, struct socket *so)
479*a9643ea8Slogwang {
480*a9643ea8Slogwang 	int error;
481*a9643ea8Slogwang 
482*a9643ea8Slogwang 	MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so,
483*a9643ea8Slogwang 	    so->so_label);
484*a9643ea8Slogwang 	MAC_CHECK_PROBE2(socket_check_visible, error, cred, so);
485*a9643ea8Slogwang 
486*a9643ea8Slogwang 	return (error);
487*a9643ea8Slogwang }
488*a9643ea8Slogwang 
489*a9643ea8Slogwang int
mac_socket_label_set(struct ucred * cred,struct socket * so,struct label * label)490*a9643ea8Slogwang mac_socket_label_set(struct ucred *cred, struct socket *so,
491*a9643ea8Slogwang     struct label *label)
492*a9643ea8Slogwang {
493*a9643ea8Slogwang 	int error;
494*a9643ea8Slogwang 
495*a9643ea8Slogwang 	/*
496*a9643ea8Slogwang 	 * We acquire the socket lock when we perform the test and set, but
497*a9643ea8Slogwang 	 * have to release it as the pcb code needs to acquire the pcb lock,
498*a9643ea8Slogwang 	 * which will precede the socket lock in the lock order.  However,
499*a9643ea8Slogwang 	 * this is fine, as any race will simply result in the inpcb being
500*a9643ea8Slogwang 	 * refreshed twice, but still consistently, as the inpcb code will
501*a9643ea8Slogwang 	 * acquire the socket lock before refreshing, holding both locks.
502*a9643ea8Slogwang 	 */
503*a9643ea8Slogwang 	SOCK_LOCK(so);
504*a9643ea8Slogwang 	error = mac_socket_check_relabel(cred, so, label);
505*a9643ea8Slogwang 	if (error) {
506*a9643ea8Slogwang 		SOCK_UNLOCK(so);
507*a9643ea8Slogwang 		return (error);
508*a9643ea8Slogwang 	}
509*a9643ea8Slogwang 
510*a9643ea8Slogwang 	mac_socket_relabel(cred, so, label);
511*a9643ea8Slogwang 	SOCK_UNLOCK(so);
512*a9643ea8Slogwang 
513*a9643ea8Slogwang 	/*
514*a9643ea8Slogwang 	 * If the protocol has expressed interest in socket layer changes,
515*a9643ea8Slogwang 	 * such as if it needs to propagate changes to a cached pcb label
516*a9643ea8Slogwang 	 * from the socket, notify it of the label change while holding the
517*a9643ea8Slogwang 	 * socket lock.
518*a9643ea8Slogwang 	 */
519*a9643ea8Slogwang 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
520*a9643ea8Slogwang 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
521*a9643ea8Slogwang 
522*a9643ea8Slogwang 	return (0);
523*a9643ea8Slogwang }
524*a9643ea8Slogwang 
525*a9643ea8Slogwang int
mac_setsockopt_label(struct ucred * cred,struct socket * so,struct mac * mac)526*a9643ea8Slogwang mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
527*a9643ea8Slogwang {
528*a9643ea8Slogwang 	struct label *intlabel;
529*a9643ea8Slogwang 	char *buffer;
530*a9643ea8Slogwang 	int error;
531*a9643ea8Slogwang 
532*a9643ea8Slogwang 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
533*a9643ea8Slogwang 		return (EINVAL);
534*a9643ea8Slogwang 
535*a9643ea8Slogwang 	error = mac_check_structmac_consistent(mac);
536*a9643ea8Slogwang 	if (error)
537*a9643ea8Slogwang 		return (error);
538*a9643ea8Slogwang 
539*a9643ea8Slogwang 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
540*a9643ea8Slogwang 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
541*a9643ea8Slogwang 	if (error) {
542*a9643ea8Slogwang 		free(buffer, M_MACTEMP);
543*a9643ea8Slogwang 		return (error);
544*a9643ea8Slogwang 	}
545*a9643ea8Slogwang 
546*a9643ea8Slogwang 	intlabel = mac_socket_label_alloc(M_WAITOK);
547*a9643ea8Slogwang 	error = mac_socket_internalize_label(intlabel, buffer);
548*a9643ea8Slogwang 	free(buffer, M_MACTEMP);
549*a9643ea8Slogwang 	if (error)
550*a9643ea8Slogwang 		goto out;
551*a9643ea8Slogwang 
552*a9643ea8Slogwang 	error = mac_socket_label_set(cred, so, intlabel);
553*a9643ea8Slogwang out:
554*a9643ea8Slogwang 	mac_socket_label_free(intlabel);
555*a9643ea8Slogwang 	return (error);
556*a9643ea8Slogwang }
557*a9643ea8Slogwang 
558*a9643ea8Slogwang int
mac_getsockopt_label(struct ucred * cred,struct socket * so,struct mac * mac)559*a9643ea8Slogwang mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
560*a9643ea8Slogwang {
561*a9643ea8Slogwang 	char *buffer, *elements;
562*a9643ea8Slogwang 	struct label *intlabel;
563*a9643ea8Slogwang 	int error;
564*a9643ea8Slogwang 
565*a9643ea8Slogwang 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
566*a9643ea8Slogwang 		return (EINVAL);
567*a9643ea8Slogwang 
568*a9643ea8Slogwang 	error = mac_check_structmac_consistent(mac);
569*a9643ea8Slogwang 	if (error)
570*a9643ea8Slogwang 		return (error);
571*a9643ea8Slogwang 
572*a9643ea8Slogwang 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
573*a9643ea8Slogwang 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
574*a9643ea8Slogwang 	if (error) {
575*a9643ea8Slogwang 		free(elements, M_MACTEMP);
576*a9643ea8Slogwang 		return (error);
577*a9643ea8Slogwang 	}
578*a9643ea8Slogwang 
579*a9643ea8Slogwang 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
580*a9643ea8Slogwang 	intlabel = mac_socket_label_alloc(M_WAITOK);
581*a9643ea8Slogwang 	SOCK_LOCK(so);
582*a9643ea8Slogwang 	mac_socket_copy_label(so->so_label, intlabel);
583*a9643ea8Slogwang 	SOCK_UNLOCK(so);
584*a9643ea8Slogwang 	error = mac_socket_externalize_label(intlabel, elements, buffer,
585*a9643ea8Slogwang 	    mac->m_buflen);
586*a9643ea8Slogwang 	mac_socket_label_free(intlabel);
587*a9643ea8Slogwang 	if (error == 0)
588*a9643ea8Slogwang 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
589*a9643ea8Slogwang 
590*a9643ea8Slogwang 	free(buffer, M_MACTEMP);
591*a9643ea8Slogwang 	free(elements, M_MACTEMP);
592*a9643ea8Slogwang 
593*a9643ea8Slogwang 	return (error);
594*a9643ea8Slogwang }
595*a9643ea8Slogwang 
596*a9643ea8Slogwang int
mac_getsockopt_peerlabel(struct ucred * cred,struct socket * so,struct mac * mac)597*a9643ea8Slogwang mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
598*a9643ea8Slogwang     struct mac *mac)
599*a9643ea8Slogwang {
600*a9643ea8Slogwang 	char *elements, *buffer;
601*a9643ea8Slogwang 	struct label *intlabel;
602*a9643ea8Slogwang 	int error;
603*a9643ea8Slogwang 
604*a9643ea8Slogwang 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
605*a9643ea8Slogwang 		return (EINVAL);
606*a9643ea8Slogwang 
607*a9643ea8Slogwang 	error = mac_check_structmac_consistent(mac);
608*a9643ea8Slogwang 	if (error)
609*a9643ea8Slogwang 		return (error);
610*a9643ea8Slogwang 
611*a9643ea8Slogwang 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
612*a9643ea8Slogwang 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
613*a9643ea8Slogwang 	if (error) {
614*a9643ea8Slogwang 		free(elements, M_MACTEMP);
615*a9643ea8Slogwang 		return (error);
616*a9643ea8Slogwang 	}
617*a9643ea8Slogwang 
618*a9643ea8Slogwang 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
619*a9643ea8Slogwang 	intlabel = mac_socket_label_alloc(M_WAITOK);
620*a9643ea8Slogwang 	SOCK_LOCK(so);
621*a9643ea8Slogwang 	mac_socket_copy_label(so->so_peerlabel, intlabel);
622*a9643ea8Slogwang 	SOCK_UNLOCK(so);
623*a9643ea8Slogwang 	error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
624*a9643ea8Slogwang 	    mac->m_buflen);
625*a9643ea8Slogwang 	mac_socket_label_free(intlabel);
626*a9643ea8Slogwang 	if (error == 0)
627*a9643ea8Slogwang 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
628*a9643ea8Slogwang 
629*a9643ea8Slogwang 	free(buffer, M_MACTEMP);
630*a9643ea8Slogwang 	free(elements, M_MACTEMP);
631*a9643ea8Slogwang 
632*a9643ea8Slogwang 	return (error);
633*a9643ea8Slogwang }
634