xref: /freebsd/sys/security/mac/mac_socket.c (revision 2087a58ca2406238cd7068bee7be3ea1065786df)
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 
10330d239bcSRobert Watson 	MAC_CHECK(socket_init_label, label, flag);
104c66b4d8dSRobert Watson 	if (error) {
10530d239bcSRobert Watson 		MAC_PERFORM(socket_destroy_label, label);
106c66b4d8dSRobert Watson 		mac_labelzone_free(label);
107c66b4d8dSRobert Watson 		return (NULL);
108c66b4d8dSRobert Watson 	}
109c66b4d8dSRobert Watson 	return (label);
110c66b4d8dSRobert Watson }
111c66b4d8dSRobert Watson 
112c66b4d8dSRobert Watson static struct label *
11330d239bcSRobert Watson mac_socketpeer_label_alloc(int flag)
114c66b4d8dSRobert Watson {
115c66b4d8dSRobert Watson 	struct label *label;
116c66b4d8dSRobert Watson 	int error;
117c66b4d8dSRobert Watson 
118c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
119c66b4d8dSRobert Watson 	if (label == NULL)
120c66b4d8dSRobert Watson 		return (NULL);
121c66b4d8dSRobert Watson 
12230d239bcSRobert Watson 	MAC_CHECK(socketpeer_init_label, label, flag);
123c66b4d8dSRobert Watson 	if (error) {
12430d239bcSRobert Watson 		MAC_PERFORM(socketpeer_destroy_label, label);
125c66b4d8dSRobert Watson 		mac_labelzone_free(label);
126c66b4d8dSRobert Watson 		return (NULL);
127c66b4d8dSRobert Watson 	}
128c66b4d8dSRobert Watson 	return (label);
129c66b4d8dSRobert Watson }
130c66b4d8dSRobert Watson 
131c66b4d8dSRobert Watson int
13230d239bcSRobert Watson mac_socket_init(struct socket *so, int flag)
133c66b4d8dSRobert Watson {
134c66b4d8dSRobert Watson 
1356356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_SOCKET) {
136c66b4d8dSRobert Watson 		so->so_label = mac_socket_label_alloc(flag);
137c66b4d8dSRobert Watson 		if (so->so_label == NULL)
138c66b4d8dSRobert Watson 			return (ENOMEM);
13930d239bcSRobert Watson 		so->so_peerlabel = mac_socketpeer_label_alloc(flag);
140c66b4d8dSRobert Watson 		if (so->so_peerlabel == NULL) {
141c66b4d8dSRobert Watson 			mac_socket_label_free(so->so_label);
142c66b4d8dSRobert Watson 			so->so_label = NULL;
143c66b4d8dSRobert Watson 			return (ENOMEM);
144c66b4d8dSRobert Watson 		}
1456356dba0SRobert Watson 	} else {
1466356dba0SRobert Watson 		so->so_label = NULL;
1476356dba0SRobert Watson 		so->so_peerlabel = NULL;
1486356dba0SRobert Watson 	}
149c66b4d8dSRobert Watson 	return (0);
150c66b4d8dSRobert Watson }
151c66b4d8dSRobert Watson 
152c66b4d8dSRobert Watson void
153c66b4d8dSRobert Watson mac_socket_label_free(struct label *label)
154c66b4d8dSRobert Watson {
155c66b4d8dSRobert Watson 
15630d239bcSRobert Watson 	MAC_PERFORM(socket_destroy_label, label);
157c66b4d8dSRobert Watson 	mac_labelzone_free(label);
158c66b4d8dSRobert Watson }
159c66b4d8dSRobert Watson 
160c66b4d8dSRobert Watson static void
16130d239bcSRobert Watson mac_socketpeer_label_free(struct label *label)
162c66b4d8dSRobert Watson {
163c66b4d8dSRobert Watson 
16430d239bcSRobert Watson 	MAC_PERFORM(socketpeer_destroy_label, label);
165c66b4d8dSRobert Watson 	mac_labelzone_free(label);
166c66b4d8dSRobert Watson }
167c66b4d8dSRobert Watson 
168c66b4d8dSRobert Watson void
16930d239bcSRobert Watson mac_socket_destroy(struct socket *so)
170c66b4d8dSRobert Watson {
171c66b4d8dSRobert Watson 
1726356dba0SRobert Watson 	if (so->so_label != NULL) {
17326ae2b86SRobert Watson 		mac_socket_label_free(so->so_label);
17426ae2b86SRobert Watson 		so->so_label = NULL;
17530d239bcSRobert Watson 		mac_socketpeer_label_free(so->so_peerlabel);
17626ae2b86SRobert Watson 		so->so_peerlabel = NULL;
177c66b4d8dSRobert Watson 	}
1786356dba0SRobert Watson }
179c66b4d8dSRobert Watson 
180c66b4d8dSRobert Watson void
18130d239bcSRobert Watson mac_socket_copy_label(struct label *src, struct label *dest)
182c66b4d8dSRobert Watson {
183c66b4d8dSRobert Watson 
18430d239bcSRobert Watson 	MAC_PERFORM(socket_copy_label, src, dest);
185c66b4d8dSRobert Watson }
186c66b4d8dSRobert Watson 
187c66b4d8dSRobert Watson int
18830d239bcSRobert Watson mac_socket_externalize_label(struct label *label, char *elements,
189c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
190c66b4d8dSRobert Watson {
191c66b4d8dSRobert Watson 	int error;
192c66b4d8dSRobert Watson 
193c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
194c66b4d8dSRobert Watson 
195c66b4d8dSRobert Watson 	return (error);
196c66b4d8dSRobert Watson }
197c66b4d8dSRobert Watson 
198c66b4d8dSRobert Watson static int
19930d239bcSRobert Watson mac_socketpeer_externalize_label(struct label *label, char *elements,
200c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
201c66b4d8dSRobert Watson {
202c66b4d8dSRobert Watson 	int error;
203c66b4d8dSRobert Watson 
20430d239bcSRobert Watson 	MAC_EXTERNALIZE(socketpeer, label, elements, outbuf, outbuflen);
205c66b4d8dSRobert Watson 
206c66b4d8dSRobert Watson 	return (error);
207c66b4d8dSRobert Watson }
208c66b4d8dSRobert Watson 
209c66b4d8dSRobert Watson int
21030d239bcSRobert Watson mac_socket_internalize_label(struct label *label, char *string)
211c66b4d8dSRobert Watson {
212c66b4d8dSRobert Watson 	int error;
213c66b4d8dSRobert Watson 
214c66b4d8dSRobert Watson 	MAC_INTERNALIZE(socket, label, string);
215c66b4d8dSRobert Watson 
216c66b4d8dSRobert Watson 	return (error);
217c66b4d8dSRobert Watson }
218c66b4d8dSRobert Watson 
219c66b4d8dSRobert Watson void
22030d239bcSRobert Watson mac_socket_create(struct ucred *cred, struct socket *so)
221c66b4d8dSRobert Watson {
222c66b4d8dSRobert Watson 
22330d239bcSRobert Watson 	MAC_PERFORM(socket_create, cred, so, so->so_label);
224c66b4d8dSRobert Watson }
225c66b4d8dSRobert Watson 
226c66b4d8dSRobert Watson void
22730d239bcSRobert Watson mac_socket_newconn(struct socket *oldso, struct socket *newso)
228c66b4d8dSRobert Watson {
229c66b4d8dSRobert Watson 
23026ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(oldso);
23126ae2b86SRobert Watson 
23230d239bcSRobert Watson 	MAC_PERFORM(socket_newconn, oldso, oldso->so_label, newso,
23326ae2b86SRobert Watson 	    newso->so_label);
234c66b4d8dSRobert Watson }
235c66b4d8dSRobert Watson 
236c66b4d8dSRobert Watson static void
23730d239bcSRobert Watson mac_socket_relabel(struct ucred *cred, struct socket *so,
238c66b4d8dSRobert Watson     struct label *newlabel)
239c66b4d8dSRobert Watson {
240c66b4d8dSRobert Watson 
24126ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
24226ae2b86SRobert Watson 
24330d239bcSRobert Watson 	MAC_PERFORM(socket_relabel, cred, so, so->so_label, newlabel);
244c66b4d8dSRobert Watson }
245c66b4d8dSRobert Watson 
246c66b4d8dSRobert Watson void
24730d239bcSRobert Watson mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
248c66b4d8dSRobert Watson {
249c66b4d8dSRobert Watson 	struct label *label;
250c66b4d8dSRobert Watson 
25126ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
252310e7cebSRobert Watson 
25326ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
254c66b4d8dSRobert Watson 
25530d239bcSRobert Watson 	MAC_PERFORM(socketpeer_set_from_mbuf, m, label, so,
25626ae2b86SRobert Watson 	    so->so_peerlabel);
257c66b4d8dSRobert Watson }
258c66b4d8dSRobert Watson 
259c66b4d8dSRobert Watson void
26030d239bcSRobert Watson mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
261c66b4d8dSRobert Watson {
262c66b4d8dSRobert Watson 
263310e7cebSRobert Watson 	/*
264df3c68e4SRobert Watson 	 * XXXRW: only hold the socket lock on one at a time, as one socket
265df3c68e4SRobert Watson 	 * is the original, and one is the new.  However, it's called in both
266df3c68e4SRobert Watson 	 * directions, so we can't assert the lock here currently.
267310e7cebSRobert Watson 	 */
26830d239bcSRobert Watson 	MAC_PERFORM(socketpeer_set_from_socket, oldso, oldso->so_label,
26926ae2b86SRobert Watson 	    newso, newso->so_peerlabel);
270c66b4d8dSRobert Watson }
271c66b4d8dSRobert Watson 
272c66b4d8dSRobert Watson void
27330d239bcSRobert Watson mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
274c66b4d8dSRobert Watson {
275c66b4d8dSRobert Watson 	struct label *label;
276c66b4d8dSRobert Watson 
27726ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
278c66b4d8dSRobert Watson 
27926ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
28026ae2b86SRobert Watson 
28130d239bcSRobert Watson 	MAC_PERFORM(socket_create_mbuf, so, so->so_label, m, label);
282c66b4d8dSRobert Watson }
283c66b4d8dSRobert Watson 
2842087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *",
2852087a58cSRobert Watson     "struct socket *");
2862087a58cSRobert Watson 
287c66b4d8dSRobert Watson int
28830d239bcSRobert Watson mac_socket_check_accept(struct ucred *cred, struct socket *so)
2897f53207bSRobert Watson {
2907f53207bSRobert Watson 	int error;
2917f53207bSRobert Watson 
29226ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
2937f53207bSRobert Watson 
29430d239bcSRobert Watson 	MAC_CHECK(socket_check_accept, cred, so, so->so_label);
2952087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_accept, error, cred, so);
2967f53207bSRobert Watson 
2977f53207bSRobert Watson 	return (error);
2987f53207bSRobert Watson }
2997f53207bSRobert Watson 
3002087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *",
3012087a58cSRobert Watson     "struct socket *", "struct sockaddr *");
3022087a58cSRobert Watson 
3037f53207bSRobert Watson int
30430d239bcSRobert Watson mac_socket_check_bind(struct ucred *ucred, struct socket *so,
30526ae2b86SRobert Watson     struct sockaddr *sa)
306c66b4d8dSRobert Watson {
307c66b4d8dSRobert Watson 	int error;
308c66b4d8dSRobert Watson 
30926ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
310310e7cebSRobert Watson 
31130d239bcSRobert Watson 	MAC_CHECK(socket_check_bind, ucred, so, so->so_label, sa);
3122087a58cSRobert Watson 	MAC_CHECK_PROBE3(socket_check_bind, error, ucred, so, sa);
313c66b4d8dSRobert Watson 
314c66b4d8dSRobert Watson 	return (error);
315c66b4d8dSRobert Watson }
316c66b4d8dSRobert Watson 
3172087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *",
3182087a58cSRobert Watson     "struct socket *", "struct sockaddr *");
3192087a58cSRobert Watson 
320c66b4d8dSRobert Watson int
32130d239bcSRobert Watson mac_socket_check_connect(struct ucred *cred, struct socket *so,
32226ae2b86SRobert Watson     struct sockaddr *sa)
323c66b4d8dSRobert Watson {
324c66b4d8dSRobert Watson 	int error;
325c66b4d8dSRobert Watson 
32626ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
327310e7cebSRobert Watson 
32830d239bcSRobert Watson 	MAC_CHECK(socket_check_connect, cred, so, so->so_label, sa);
3292087a58cSRobert Watson 	MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa);
330c66b4d8dSRobert Watson 
331c66b4d8dSRobert Watson 	return (error);
332c66b4d8dSRobert Watson }
333c66b4d8dSRobert Watson 
3342087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int",
3352087a58cSRobert Watson     "int");
3362087a58cSRobert Watson 
337c66b4d8dSRobert Watson int
33830d239bcSRobert Watson mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
3396758f88eSRobert Watson {
3406758f88eSRobert Watson 	int error;
3416758f88eSRobert Watson 
34230d239bcSRobert Watson 	MAC_CHECK(socket_check_create, cred, domain, type, proto);
3432087a58cSRobert Watson 	MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type,
3442087a58cSRobert Watson 	    proto);
3456758f88eSRobert Watson 
3466758f88eSRobert Watson 	return (error);
3476758f88eSRobert Watson }
3486758f88eSRobert Watson 
3492087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *",
3502087a58cSRobert Watson     "struct mbuf *");
3512087a58cSRobert Watson 
3526758f88eSRobert Watson int
35330d239bcSRobert Watson mac_socket_check_deliver(struct socket *so, struct mbuf *m)
354c66b4d8dSRobert Watson {
355c66b4d8dSRobert Watson 	struct label *label;
356c66b4d8dSRobert Watson 	int error;
357c66b4d8dSRobert Watson 
35826ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
359310e7cebSRobert Watson 
36026ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
361c66b4d8dSRobert Watson 
36230d239bcSRobert Watson 	MAC_CHECK(socket_check_deliver, so, so->so_label, m, label);
3632087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_deliver, error, so, m);
364c66b4d8dSRobert Watson 
365c66b4d8dSRobert Watson 	return (error);
366c66b4d8dSRobert Watson }
367c66b4d8dSRobert Watson 
3682087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *",
3692087a58cSRobert Watson     "struct socket *");
3702087a58cSRobert Watson 
371c66b4d8dSRobert Watson int
37230d239bcSRobert Watson mac_socket_check_listen(struct ucred *cred, struct socket *so)
373c66b4d8dSRobert Watson {
374c66b4d8dSRobert Watson 	int error;
375c66b4d8dSRobert Watson 
37626ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
377310e7cebSRobert Watson 
37830d239bcSRobert Watson 	MAC_CHECK(socket_check_listen, cred, so, so->so_label);
3792087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_listen, error, cred, so);
38026ae2b86SRobert Watson 
381c66b4d8dSRobert Watson 	return (error);
382c66b4d8dSRobert Watson }
383c66b4d8dSRobert Watson 
3842087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *",
3852087a58cSRobert Watson     "struct socket *");
3862087a58cSRobert Watson 
387c66b4d8dSRobert Watson int
38830d239bcSRobert Watson mac_socket_check_poll(struct ucred *cred, struct socket *so)
3897f53207bSRobert Watson {
3907f53207bSRobert Watson 	int error;
3917f53207bSRobert Watson 
3927f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
3937f53207bSRobert Watson 
39430d239bcSRobert Watson 	MAC_CHECK(socket_check_poll, cred, so, so->so_label);
3952087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_poll, error, cred, so);
39626ae2b86SRobert Watson 
3977f53207bSRobert Watson 	return (error);
3987f53207bSRobert Watson }
3997f53207bSRobert Watson 
4002087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *",
4012087a58cSRobert Watson     "struct socket *");
4022087a58cSRobert Watson 
4037f53207bSRobert Watson int
40430d239bcSRobert Watson mac_socket_check_receive(struct ucred *cred, struct socket *so)
405c66b4d8dSRobert Watson {
406c66b4d8dSRobert Watson 	int error;
407c66b4d8dSRobert Watson 
408310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
409310e7cebSRobert Watson 
41030d239bcSRobert Watson 	MAC_CHECK(socket_check_receive, cred, so, so->so_label);
4112087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_receive, error, cred, so);
412c66b4d8dSRobert Watson 
413c66b4d8dSRobert Watson 	return (error);
414c66b4d8dSRobert Watson }
415c66b4d8dSRobert Watson 
4162087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *",
4172087a58cSRobert Watson     "struct socket *", "struct label *");
4182087a58cSRobert Watson 
419c66b4d8dSRobert Watson static int
42030d239bcSRobert Watson mac_socket_check_relabel(struct ucred *cred, struct socket *so,
421c66b4d8dSRobert Watson     struct label *newlabel)
422c66b4d8dSRobert Watson {
423c66b4d8dSRobert Watson 	int error;
424c66b4d8dSRobert Watson 
42526ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
426310e7cebSRobert Watson 
42730d239bcSRobert Watson 	MAC_CHECK(socket_check_relabel, cred, so, so->so_label, newlabel);
4282087a58cSRobert Watson 	MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel);
429c66b4d8dSRobert Watson 
430c66b4d8dSRobert Watson 	return (error);
431c66b4d8dSRobert Watson }
432c66b4d8dSRobert Watson 
4332087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *",
4342087a58cSRobert Watson     "struct socket *");
4352087a58cSRobert Watson 
436c66b4d8dSRobert Watson int
43730d239bcSRobert Watson mac_socket_check_send(struct ucred *cred, struct socket *so)
438c66b4d8dSRobert Watson {
439c66b4d8dSRobert Watson 	int error;
440c66b4d8dSRobert Watson 
441310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
442310e7cebSRobert Watson 
44330d239bcSRobert Watson 	MAC_CHECK(socket_check_send, cred, so, so->so_label);
4442087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_send, error, cred, so);
445c66b4d8dSRobert Watson 
446c66b4d8dSRobert Watson 	return (error);
447c66b4d8dSRobert Watson }
448c66b4d8dSRobert Watson 
4492087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *",
4502087a58cSRobert Watson     "struct socket *");
4512087a58cSRobert Watson 
452c66b4d8dSRobert Watson int
45330d239bcSRobert Watson mac_socket_check_stat(struct ucred *cred, struct socket *so)
4547f53207bSRobert Watson {
4557f53207bSRobert Watson 	int error;
4567f53207bSRobert Watson 
4577f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
4587f53207bSRobert Watson 
45930d239bcSRobert Watson 	MAC_CHECK(socket_check_stat, cred, so, so->so_label);
4602087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_stat, error, cred, so);
4617f53207bSRobert Watson 
4627f53207bSRobert Watson 	return (error);
4637f53207bSRobert Watson }
4647f53207bSRobert Watson 
4652087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *",
4662087a58cSRobert Watson     "struct socket *");
4672087a58cSRobert Watson 
4687f53207bSRobert Watson int
46930d239bcSRobert Watson mac_socket_check_visible(struct ucred *cred, struct socket *so)
470c66b4d8dSRobert Watson {
471c66b4d8dSRobert Watson 	int error;
472c66b4d8dSRobert Watson 
47326ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
474310e7cebSRobert Watson 
47530d239bcSRobert Watson 	MAC_CHECK(socket_check_visible, cred, so, so->so_label);
4762087a58cSRobert Watson 	MAC_CHECK_PROBE2(socket_check_visible, error, cred, so);
477c66b4d8dSRobert Watson 
478c66b4d8dSRobert Watson 	return (error);
479c66b4d8dSRobert Watson }
480c66b4d8dSRobert Watson 
481c66b4d8dSRobert Watson int
482c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so,
483c66b4d8dSRobert Watson     struct label *label)
484c66b4d8dSRobert Watson {
485c66b4d8dSRobert Watson 	int error;
486c66b4d8dSRobert Watson 
487310e7cebSRobert Watson 	/*
488df3c68e4SRobert Watson 	 * We acquire the socket lock when we perform the test and set, but
489df3c68e4SRobert Watson 	 * have to release it as the pcb code needs to acquire the pcb lock,
490df3c68e4SRobert Watson 	 * which will precede the socket lock in the lock order.  However,
491df3c68e4SRobert Watson 	 * this is fine, as any race will simply result in the inpcb being
492df3c68e4SRobert Watson 	 * refreshed twice, but still consistently, as the inpcb code will
493df3c68e4SRobert Watson 	 * acquire the socket lock before refreshing, holding both locks.
494310e7cebSRobert Watson 	 */
495310e7cebSRobert Watson 	SOCK_LOCK(so);
49630d239bcSRobert Watson 	error = mac_socket_check_relabel(cred, so, label);
497310e7cebSRobert Watson 	if (error) {
498310e7cebSRobert Watson 		SOCK_UNLOCK(so);
499c66b4d8dSRobert Watson 		return (error);
500310e7cebSRobert Watson 	}
501c66b4d8dSRobert Watson 
50230d239bcSRobert Watson 	mac_socket_relabel(cred, so, label);
503310e7cebSRobert Watson 	SOCK_UNLOCK(so);
504df3c68e4SRobert Watson 
505c66b4d8dSRobert Watson 	/*
506c66b4d8dSRobert Watson 	 * If the protocol has expressed interest in socket layer changes,
507df3c68e4SRobert Watson 	 * such as if it needs to propagate changes to a cached pcb label
508df3c68e4SRobert Watson 	 * from the socket, notify it of the label change while holding the
509df3c68e4SRobert Watson 	 * socket lock.
510c66b4d8dSRobert Watson 	 */
511c66b4d8dSRobert Watson 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
512c66b4d8dSRobert Watson 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
513c66b4d8dSRobert Watson 
514c66b4d8dSRobert Watson 	return (0);
515c66b4d8dSRobert Watson }
516c66b4d8dSRobert Watson 
517c66b4d8dSRobert Watson int
518c66b4d8dSRobert Watson mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
519c66b4d8dSRobert Watson {
520c66b4d8dSRobert Watson 	struct label *intlabel;
521c66b4d8dSRobert Watson 	char *buffer;
522c66b4d8dSRobert Watson 	int error;
523c66b4d8dSRobert Watson 
5246356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
5256356dba0SRobert Watson 		return (EINVAL);
5266356dba0SRobert Watson 
527c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
528c66b4d8dSRobert Watson 	if (error)
529c66b4d8dSRobert Watson 		return (error);
530c66b4d8dSRobert Watson 
531c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
532c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
533c66b4d8dSRobert Watson 	if (error) {
534c66b4d8dSRobert Watson 		free(buffer, M_MACTEMP);
535c66b4d8dSRobert Watson 		return (error);
536c66b4d8dSRobert Watson 	}
537c66b4d8dSRobert Watson 
538c66b4d8dSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
53930d239bcSRobert Watson 	error = mac_socket_internalize_label(intlabel, buffer);
540c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
541c66b4d8dSRobert Watson 	if (error)
542c66b4d8dSRobert Watson 		goto out;
543c66b4d8dSRobert Watson 
544c66b4d8dSRobert Watson 	error = mac_socket_label_set(cred, so, intlabel);
545c66b4d8dSRobert Watson out:
546c66b4d8dSRobert Watson 	mac_socket_label_free(intlabel);
547c66b4d8dSRobert Watson 	return (error);
548c66b4d8dSRobert Watson }
549c66b4d8dSRobert Watson 
550c66b4d8dSRobert Watson int
551c66b4d8dSRobert Watson mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
552c66b4d8dSRobert Watson {
553c66b4d8dSRobert Watson 	char *buffer, *elements;
554310e7cebSRobert Watson 	struct label *intlabel;
555c66b4d8dSRobert Watson 	int error;
556c66b4d8dSRobert Watson 
5576356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
5586356dba0SRobert Watson 		return (EINVAL);
5596356dba0SRobert Watson 
560c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
561c66b4d8dSRobert Watson 	if (error)
562c66b4d8dSRobert Watson 		return (error);
563c66b4d8dSRobert Watson 
564c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
565c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
566c66b4d8dSRobert Watson 	if (error) {
567c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
568c66b4d8dSRobert Watson 		return (error);
569c66b4d8dSRobert Watson 	}
570c66b4d8dSRobert Watson 
571c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
572310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
573310e7cebSRobert Watson 	SOCK_LOCK(so);
57430d239bcSRobert Watson 	mac_socket_copy_label(so->so_label, intlabel);
575310e7cebSRobert Watson 	SOCK_UNLOCK(so);
57630d239bcSRobert Watson 	error = mac_socket_externalize_label(intlabel, elements, buffer,
577310e7cebSRobert Watson 	    mac->m_buflen);
578310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
579c66b4d8dSRobert Watson 	if (error == 0)
580c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
581c66b4d8dSRobert Watson 
582c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
583c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
584c66b4d8dSRobert Watson 
585c66b4d8dSRobert Watson 	return (error);
586c66b4d8dSRobert Watson }
587c66b4d8dSRobert Watson 
588c66b4d8dSRobert Watson int
589c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
590c66b4d8dSRobert Watson     struct mac *mac)
591c66b4d8dSRobert Watson {
592c66b4d8dSRobert Watson 	char *elements, *buffer;
593310e7cebSRobert Watson 	struct label *intlabel;
594c66b4d8dSRobert Watson 	int error;
595c66b4d8dSRobert Watson 
5966356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
5976356dba0SRobert Watson 		return (EINVAL);
5986356dba0SRobert Watson 
599c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
600c66b4d8dSRobert Watson 	if (error)
601c66b4d8dSRobert Watson 		return (error);
602c66b4d8dSRobert Watson 
603c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
604c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
605c66b4d8dSRobert Watson 	if (error) {
606c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
607c66b4d8dSRobert Watson 		return (error);
608c66b4d8dSRobert Watson 	}
609c66b4d8dSRobert Watson 
610c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
611310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
612310e7cebSRobert Watson 	SOCK_LOCK(so);
61330d239bcSRobert Watson 	mac_socket_copy_label(so->so_peerlabel, intlabel);
614310e7cebSRobert Watson 	SOCK_UNLOCK(so);
61530d239bcSRobert Watson 	error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
616310e7cebSRobert Watson 	    mac->m_buflen);
617310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
618c66b4d8dSRobert Watson 	if (error == 0)
619c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
620c66b4d8dSRobert Watson 
621c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
622c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
623c66b4d8dSRobert Watson 
624c66b4d8dSRobert Watson 	return (error);
625c66b4d8dSRobert Watson }
626