xref: /freebsd/sys/security/mac/mac_socket.c (revision 6356dba0b403daa023dec24559ab1f8e602e4f14)
1c66b4d8dSRobert Watson /*-
2c66b4d8dSRobert Watson  * Copyright (c) 1999-2002 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  *
20c66b4d8dSRobert Watson  * Redistribution and use in source and binary forms, with or without
21c66b4d8dSRobert Watson  * modification, are permitted provided that the following conditions
22c66b4d8dSRobert Watson  * are met:
23c66b4d8dSRobert Watson  * 1. Redistributions of source code must retain the above copyright
24c66b4d8dSRobert Watson  *    notice, this list of conditions and the following disclaimer.
25c66b4d8dSRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
26c66b4d8dSRobert Watson  *    notice, this list of conditions and the following disclaimer in the
27c66b4d8dSRobert Watson  *    documentation and/or other materials provided with the distribution.
28c66b4d8dSRobert Watson  *
29c66b4d8dSRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30c66b4d8dSRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31c66b4d8dSRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32c66b4d8dSRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33c66b4d8dSRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34c66b4d8dSRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35c66b4d8dSRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36c66b4d8dSRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37c66b4d8dSRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38c66b4d8dSRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39c66b4d8dSRobert Watson  * SUCH DAMAGE.
40c66b4d8dSRobert Watson  */
41c66b4d8dSRobert Watson 
42c66b4d8dSRobert Watson #include <sys/cdefs.h>
43c66b4d8dSRobert Watson __FBSDID("$FreeBSD$");
44c66b4d8dSRobert Watson 
45c66b4d8dSRobert Watson #include "opt_mac.h"
46c66b4d8dSRobert Watson 
47c66b4d8dSRobert Watson #include <sys/param.h>
48c66b4d8dSRobert Watson #include <sys/kernel.h>
49c66b4d8dSRobert Watson #include <sys/lock.h>
50c66b4d8dSRobert Watson #include <sys/malloc.h>
51c66b4d8dSRobert Watson #include <sys/mutex.h>
52c66b4d8dSRobert Watson #include <sys/mac.h>
53c66b4d8dSRobert Watson #include <sys/sbuf.h>
54c66b4d8dSRobert Watson #include <sys/systm.h>
55c66b4d8dSRobert Watson #include <sys/mount.h>
56c66b4d8dSRobert Watson #include <sys/file.h>
57c66b4d8dSRobert Watson #include <sys/namei.h>
58c66b4d8dSRobert Watson #include <sys/protosw.h>
59c66b4d8dSRobert Watson #include <sys/socket.h>
60c66b4d8dSRobert Watson #include <sys/socketvar.h>
61c66b4d8dSRobert Watson #include <sys/sysctl.h>
62c66b4d8dSRobert Watson 
63c66b4d8dSRobert Watson #include <net/bpfdesc.h>
64c66b4d8dSRobert Watson #include <net/if.h>
65c66b4d8dSRobert Watson #include <net/if_var.h>
66c66b4d8dSRobert Watson 
67c66b4d8dSRobert Watson #include <netinet/in.h>
68c66b4d8dSRobert Watson #include <netinet/in_pcb.h>
69c66b4d8dSRobert Watson #include <netinet/ip_var.h>
70c66b4d8dSRobert Watson 
71aed55708SRobert Watson #include <security/mac/mac_framework.h>
72c66b4d8dSRobert Watson #include <security/mac/mac_internal.h>
730efd6615SRobert Watson #include <security/mac/mac_policy.h>
74c66b4d8dSRobert Watson 
75c66b4d8dSRobert Watson /*
76df3c68e4SRobert Watson  * Currently, sockets hold two labels: the label of the socket itself, and a
77df3c68e4SRobert Watson  * peer label, which may be used by policies to hold a copy of the label of
78df3c68e4SRobert Watson  * any remote endpoint.
79df3c68e4SRobert Watson  *
80df3c68e4SRobert Watson  * Possibly, this peer label should be maintained at the protocol layer
81df3c68e4SRobert Watson  * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
82df3c68e4SRobert Watson  * the label consistently.  For example, it might be copied live from a
83df3c68e4SRobert Watson  * remote socket for UNIX domain sockets rather than keeping a local copy on
84df3c68e4SRobert Watson  * this endpoint, but be cached and updated based on packets received for
85df3c68e4SRobert Watson  * TCP/IP.
86df3c68e4SRobert Watson  */
87df3c68e4SRobert Watson 
88c66b4d8dSRobert Watson struct label *
89c66b4d8dSRobert Watson mac_socket_label_alloc(int flag)
90c66b4d8dSRobert Watson {
91c66b4d8dSRobert Watson 	struct label *label;
92c66b4d8dSRobert Watson 	int error;
93c66b4d8dSRobert Watson 
94c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
95c66b4d8dSRobert Watson 	if (label == NULL)
96c66b4d8dSRobert Watson 		return (NULL);
97c66b4d8dSRobert Watson 
9830d239bcSRobert Watson 	MAC_CHECK(socket_init_label, label, flag);
99c66b4d8dSRobert Watson 	if (error) {
10030d239bcSRobert Watson 		MAC_PERFORM(socket_destroy_label, label);
101c66b4d8dSRobert Watson 		mac_labelzone_free(label);
102c66b4d8dSRobert Watson 		return (NULL);
103c66b4d8dSRobert Watson 	}
104c66b4d8dSRobert Watson 	return (label);
105c66b4d8dSRobert Watson }
106c66b4d8dSRobert Watson 
107c66b4d8dSRobert Watson static struct label *
10830d239bcSRobert Watson mac_socketpeer_label_alloc(int flag)
109c66b4d8dSRobert Watson {
110c66b4d8dSRobert Watson 	struct label *label;
111c66b4d8dSRobert Watson 	int error;
112c66b4d8dSRobert Watson 
113c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
114c66b4d8dSRobert Watson 	if (label == NULL)
115c66b4d8dSRobert Watson 		return (NULL);
116c66b4d8dSRobert Watson 
11730d239bcSRobert Watson 	MAC_CHECK(socketpeer_init_label, label, flag);
118c66b4d8dSRobert Watson 	if (error) {
11930d239bcSRobert Watson 		MAC_PERFORM(socketpeer_destroy_label, label);
120c66b4d8dSRobert Watson 		mac_labelzone_free(label);
121c66b4d8dSRobert Watson 		return (NULL);
122c66b4d8dSRobert Watson 	}
123c66b4d8dSRobert Watson 	return (label);
124c66b4d8dSRobert Watson }
125c66b4d8dSRobert Watson 
126c66b4d8dSRobert Watson int
12730d239bcSRobert Watson mac_socket_init(struct socket *so, int flag)
128c66b4d8dSRobert Watson {
129c66b4d8dSRobert Watson 
1306356dba0SRobert Watson 	if (mac_labeled & MPC_OBJECT_SOCKET) {
131c66b4d8dSRobert Watson 		so->so_label = mac_socket_label_alloc(flag);
132c66b4d8dSRobert Watson 		if (so->so_label == NULL)
133c66b4d8dSRobert Watson 			return (ENOMEM);
13430d239bcSRobert Watson 		so->so_peerlabel = mac_socketpeer_label_alloc(flag);
135c66b4d8dSRobert Watson 		if (so->so_peerlabel == NULL) {
136c66b4d8dSRobert Watson 			mac_socket_label_free(so->so_label);
137c66b4d8dSRobert Watson 			so->so_label = NULL;
138c66b4d8dSRobert Watson 			return (ENOMEM);
139c66b4d8dSRobert Watson 		}
1406356dba0SRobert Watson 	} else {
1416356dba0SRobert Watson 		so->so_label = NULL;
1426356dba0SRobert Watson 		so->so_peerlabel = NULL;
1436356dba0SRobert Watson 	}
144c66b4d8dSRobert Watson 	return (0);
145c66b4d8dSRobert Watson }
146c66b4d8dSRobert Watson 
147c66b4d8dSRobert Watson void
148c66b4d8dSRobert Watson mac_socket_label_free(struct label *label)
149c66b4d8dSRobert Watson {
150c66b4d8dSRobert Watson 
15130d239bcSRobert Watson 	MAC_PERFORM(socket_destroy_label, label);
152c66b4d8dSRobert Watson 	mac_labelzone_free(label);
153c66b4d8dSRobert Watson }
154c66b4d8dSRobert Watson 
155c66b4d8dSRobert Watson static void
15630d239bcSRobert Watson mac_socketpeer_label_free(struct label *label)
157c66b4d8dSRobert Watson {
158c66b4d8dSRobert Watson 
15930d239bcSRobert Watson 	MAC_PERFORM(socketpeer_destroy_label, label);
160c66b4d8dSRobert Watson 	mac_labelzone_free(label);
161c66b4d8dSRobert Watson }
162c66b4d8dSRobert Watson 
163c66b4d8dSRobert Watson void
16430d239bcSRobert Watson mac_socket_destroy(struct socket *so)
165c66b4d8dSRobert Watson {
166c66b4d8dSRobert Watson 
1676356dba0SRobert Watson 	if (so->so_label != NULL) {
16826ae2b86SRobert Watson 		mac_socket_label_free(so->so_label);
16926ae2b86SRobert Watson 		so->so_label = NULL;
17030d239bcSRobert Watson 		mac_socketpeer_label_free(so->so_peerlabel);
17126ae2b86SRobert Watson 		so->so_peerlabel = NULL;
172c66b4d8dSRobert Watson 	}
1736356dba0SRobert Watson }
174c66b4d8dSRobert Watson 
175c66b4d8dSRobert Watson void
17630d239bcSRobert Watson mac_socket_copy_label(struct label *src, struct label *dest)
177c66b4d8dSRobert Watson {
178c66b4d8dSRobert Watson 
17930d239bcSRobert Watson 	MAC_PERFORM(socket_copy_label, src, dest);
180c66b4d8dSRobert Watson }
181c66b4d8dSRobert Watson 
182c66b4d8dSRobert Watson int
18330d239bcSRobert Watson mac_socket_externalize_label(struct label *label, char *elements,
184c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
185c66b4d8dSRobert Watson {
186c66b4d8dSRobert Watson 	int error;
187c66b4d8dSRobert Watson 
188c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
189c66b4d8dSRobert Watson 
190c66b4d8dSRobert Watson 	return (error);
191c66b4d8dSRobert Watson }
192c66b4d8dSRobert Watson 
193c66b4d8dSRobert Watson static int
19430d239bcSRobert Watson mac_socketpeer_externalize_label(struct label *label, char *elements,
195c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
196c66b4d8dSRobert Watson {
197c66b4d8dSRobert Watson 	int error;
198c66b4d8dSRobert Watson 
19930d239bcSRobert Watson 	MAC_EXTERNALIZE(socketpeer, label, elements, outbuf, outbuflen);
200c66b4d8dSRobert Watson 
201c66b4d8dSRobert Watson 	return (error);
202c66b4d8dSRobert Watson }
203c66b4d8dSRobert Watson 
204c66b4d8dSRobert Watson int
20530d239bcSRobert Watson mac_socket_internalize_label(struct label *label, char *string)
206c66b4d8dSRobert Watson {
207c66b4d8dSRobert Watson 	int error;
208c66b4d8dSRobert Watson 
209c66b4d8dSRobert Watson 	MAC_INTERNALIZE(socket, label, string);
210c66b4d8dSRobert Watson 
211c66b4d8dSRobert Watson 	return (error);
212c66b4d8dSRobert Watson }
213c66b4d8dSRobert Watson 
214c66b4d8dSRobert Watson void
21530d239bcSRobert Watson mac_socket_create(struct ucred *cred, struct socket *so)
216c66b4d8dSRobert Watson {
217c66b4d8dSRobert Watson 
21830d239bcSRobert Watson 	MAC_PERFORM(socket_create, cred, so, so->so_label);
219c66b4d8dSRobert Watson }
220c66b4d8dSRobert Watson 
221c66b4d8dSRobert Watson void
22230d239bcSRobert Watson mac_socket_newconn(struct socket *oldso, struct socket *newso)
223c66b4d8dSRobert Watson {
224c66b4d8dSRobert Watson 
22526ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(oldso);
22626ae2b86SRobert Watson 
22730d239bcSRobert Watson 	MAC_PERFORM(socket_newconn, oldso, oldso->so_label, newso,
22826ae2b86SRobert Watson 	    newso->so_label);
229c66b4d8dSRobert Watson }
230c66b4d8dSRobert Watson 
231c66b4d8dSRobert Watson static void
23230d239bcSRobert Watson mac_socket_relabel(struct ucred *cred, struct socket *so,
233c66b4d8dSRobert Watson     struct label *newlabel)
234c66b4d8dSRobert Watson {
235c66b4d8dSRobert Watson 
23626ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
23726ae2b86SRobert Watson 
23830d239bcSRobert Watson 	MAC_PERFORM(socket_relabel, cred, so, so->so_label, newlabel);
239c66b4d8dSRobert Watson }
240c66b4d8dSRobert Watson 
241c66b4d8dSRobert Watson void
24230d239bcSRobert Watson mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
243c66b4d8dSRobert Watson {
244c66b4d8dSRobert Watson 	struct label *label;
245c66b4d8dSRobert Watson 
24626ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
247310e7cebSRobert Watson 
24826ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
249c66b4d8dSRobert Watson 
25030d239bcSRobert Watson 	MAC_PERFORM(socketpeer_set_from_mbuf, m, label, so,
25126ae2b86SRobert Watson 	    so->so_peerlabel);
252c66b4d8dSRobert Watson }
253c66b4d8dSRobert Watson 
254c66b4d8dSRobert Watson void
25530d239bcSRobert Watson mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
256c66b4d8dSRobert Watson {
257c66b4d8dSRobert Watson 
258310e7cebSRobert Watson 	/*
259df3c68e4SRobert Watson 	 * XXXRW: only hold the socket lock on one at a time, as one socket
260df3c68e4SRobert Watson 	 * is the original, and one is the new.  However, it's called in both
261df3c68e4SRobert Watson 	 * directions, so we can't assert the lock here currently.
262310e7cebSRobert Watson 	 */
26330d239bcSRobert Watson 	MAC_PERFORM(socketpeer_set_from_socket, oldso, oldso->so_label,
26426ae2b86SRobert Watson 	    newso, newso->so_peerlabel);
265c66b4d8dSRobert Watson }
266c66b4d8dSRobert Watson 
267c66b4d8dSRobert Watson void
26830d239bcSRobert Watson mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
269c66b4d8dSRobert Watson {
270c66b4d8dSRobert Watson 	struct label *label;
271c66b4d8dSRobert Watson 
27226ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
273c66b4d8dSRobert Watson 
27426ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
27526ae2b86SRobert Watson 
27630d239bcSRobert Watson 	MAC_PERFORM(socket_create_mbuf, so, so->so_label, m, label);
277c66b4d8dSRobert Watson }
278c66b4d8dSRobert Watson 
279c66b4d8dSRobert Watson int
28030d239bcSRobert Watson mac_socket_check_accept(struct ucred *cred, struct socket *so)
2817f53207bSRobert Watson {
2827f53207bSRobert Watson 	int error;
2837f53207bSRobert Watson 
28426ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
2857f53207bSRobert Watson 
28630d239bcSRobert Watson 	MAC_CHECK(socket_check_accept, cred, so, so->so_label);
2877f53207bSRobert Watson 
2887f53207bSRobert Watson 	return (error);
2897f53207bSRobert Watson }
2907f53207bSRobert Watson 
2917f53207bSRobert Watson int
29230d239bcSRobert Watson mac_socket_check_bind(struct ucred *ucred, struct socket *so,
29326ae2b86SRobert Watson     struct sockaddr *sa)
294c66b4d8dSRobert Watson {
295c66b4d8dSRobert Watson 	int error;
296c66b4d8dSRobert Watson 
29726ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
298310e7cebSRobert Watson 
29930d239bcSRobert Watson 	MAC_CHECK(socket_check_bind, ucred, so, so->so_label, sa);
300c66b4d8dSRobert Watson 
301c66b4d8dSRobert Watson 	return (error);
302c66b4d8dSRobert Watson }
303c66b4d8dSRobert Watson 
304c66b4d8dSRobert Watson int
30530d239bcSRobert Watson mac_socket_check_connect(struct ucred *cred, struct socket *so,
30626ae2b86SRobert Watson     struct sockaddr *sa)
307c66b4d8dSRobert Watson {
308c66b4d8dSRobert Watson 	int error;
309c66b4d8dSRobert Watson 
31026ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
311310e7cebSRobert Watson 
31230d239bcSRobert Watson 	MAC_CHECK(socket_check_connect, cred, so, so->so_label, sa);
313c66b4d8dSRobert Watson 
314c66b4d8dSRobert Watson 	return (error);
315c66b4d8dSRobert Watson }
316c66b4d8dSRobert Watson 
317c66b4d8dSRobert Watson int
31830d239bcSRobert Watson mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
3196758f88eSRobert Watson {
3206758f88eSRobert Watson 	int error;
3216758f88eSRobert Watson 
32230d239bcSRobert Watson 	MAC_CHECK(socket_check_create, cred, domain, type, proto);
3236758f88eSRobert Watson 
3246758f88eSRobert Watson 	return (error);
3256758f88eSRobert Watson }
3266758f88eSRobert Watson 
3276758f88eSRobert Watson int
32830d239bcSRobert Watson mac_socket_check_deliver(struct socket *so, struct mbuf *m)
329c66b4d8dSRobert Watson {
330c66b4d8dSRobert Watson 	struct label *label;
331c66b4d8dSRobert Watson 	int error;
332c66b4d8dSRobert Watson 
33326ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
334310e7cebSRobert Watson 
33526ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
336c66b4d8dSRobert Watson 
33730d239bcSRobert Watson 	MAC_CHECK(socket_check_deliver, so, so->so_label, m, label);
338c66b4d8dSRobert Watson 
339c66b4d8dSRobert Watson 	return (error);
340c66b4d8dSRobert Watson }
341c66b4d8dSRobert Watson 
342c66b4d8dSRobert Watson int
34330d239bcSRobert Watson mac_socket_check_listen(struct ucred *cred, struct socket *so)
344c66b4d8dSRobert Watson {
345c66b4d8dSRobert Watson 	int error;
346c66b4d8dSRobert Watson 
34726ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
348310e7cebSRobert Watson 
34930d239bcSRobert Watson 	MAC_CHECK(socket_check_listen, cred, so, so->so_label);
35026ae2b86SRobert Watson 
351c66b4d8dSRobert Watson 	return (error);
352c66b4d8dSRobert Watson }
353c66b4d8dSRobert Watson 
354c66b4d8dSRobert Watson int
35530d239bcSRobert Watson mac_socket_check_poll(struct ucred *cred, struct socket *so)
3567f53207bSRobert Watson {
3577f53207bSRobert Watson 	int error;
3587f53207bSRobert Watson 
3597f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
3607f53207bSRobert Watson 
36130d239bcSRobert Watson 	MAC_CHECK(socket_check_poll, cred, so, so->so_label);
36226ae2b86SRobert Watson 
3637f53207bSRobert Watson 	return (error);
3647f53207bSRobert Watson }
3657f53207bSRobert Watson 
3667f53207bSRobert Watson int
36730d239bcSRobert Watson mac_socket_check_receive(struct ucred *cred, struct socket *so)
368c66b4d8dSRobert Watson {
369c66b4d8dSRobert Watson 	int error;
370c66b4d8dSRobert Watson 
371310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
372310e7cebSRobert Watson 
37330d239bcSRobert Watson 	MAC_CHECK(socket_check_receive, cred, so, so->so_label);
374c66b4d8dSRobert Watson 
375c66b4d8dSRobert Watson 	return (error);
376c66b4d8dSRobert Watson }
377c66b4d8dSRobert Watson 
378c66b4d8dSRobert Watson static int
37930d239bcSRobert Watson mac_socket_check_relabel(struct ucred *cred, struct socket *so,
380c66b4d8dSRobert Watson     struct label *newlabel)
381c66b4d8dSRobert Watson {
382c66b4d8dSRobert Watson 	int error;
383c66b4d8dSRobert Watson 
38426ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
385310e7cebSRobert Watson 
38630d239bcSRobert Watson 	MAC_CHECK(socket_check_relabel, cred, so, so->so_label, newlabel);
387c66b4d8dSRobert Watson 
388c66b4d8dSRobert Watson 	return (error);
389c66b4d8dSRobert Watson }
390c66b4d8dSRobert Watson 
391c66b4d8dSRobert Watson int
39230d239bcSRobert Watson mac_socket_check_send(struct ucred *cred, struct socket *so)
393c66b4d8dSRobert Watson {
394c66b4d8dSRobert Watson 	int error;
395c66b4d8dSRobert Watson 
396310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
397310e7cebSRobert Watson 
39830d239bcSRobert Watson 	MAC_CHECK(socket_check_send, cred, so, so->so_label);
399c66b4d8dSRobert Watson 
400c66b4d8dSRobert Watson 	return (error);
401c66b4d8dSRobert Watson }
402c66b4d8dSRobert Watson 
403c66b4d8dSRobert Watson int
40430d239bcSRobert Watson mac_socket_check_stat(struct ucred *cred, struct socket *so)
4057f53207bSRobert Watson {
4067f53207bSRobert Watson 	int error;
4077f53207bSRobert Watson 
4087f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
4097f53207bSRobert Watson 
41030d239bcSRobert Watson 	MAC_CHECK(socket_check_stat, cred, so, so->so_label);
4117f53207bSRobert Watson 
4127f53207bSRobert Watson 	return (error);
4137f53207bSRobert Watson }
4147f53207bSRobert Watson 
4157f53207bSRobert Watson int
41630d239bcSRobert Watson mac_socket_check_visible(struct ucred *cred, struct socket *so)
417c66b4d8dSRobert Watson {
418c66b4d8dSRobert Watson 	int error;
419c66b4d8dSRobert Watson 
42026ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
421310e7cebSRobert Watson 
42230d239bcSRobert Watson 	MAC_CHECK(socket_check_visible, cred, so, so->so_label);
423c66b4d8dSRobert Watson 
424c66b4d8dSRobert Watson 	return (error);
425c66b4d8dSRobert Watson }
426c66b4d8dSRobert Watson 
427c66b4d8dSRobert Watson int
428c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so,
429c66b4d8dSRobert Watson     struct label *label)
430c66b4d8dSRobert Watson {
431c66b4d8dSRobert Watson 	int error;
432c66b4d8dSRobert Watson 
433310e7cebSRobert Watson 	/*
434df3c68e4SRobert Watson 	 * We acquire the socket lock when we perform the test and set, but
435df3c68e4SRobert Watson 	 * have to release it as the pcb code needs to acquire the pcb lock,
436df3c68e4SRobert Watson 	 * which will precede the socket lock in the lock order.  However,
437df3c68e4SRobert Watson 	 * this is fine, as any race will simply result in the inpcb being
438df3c68e4SRobert Watson 	 * refreshed twice, but still consistently, as the inpcb code will
439df3c68e4SRobert Watson 	 * acquire the socket lock before refreshing, holding both locks.
440310e7cebSRobert Watson 	 */
441310e7cebSRobert Watson 	SOCK_LOCK(so);
44230d239bcSRobert Watson 	error = mac_socket_check_relabel(cred, so, label);
443310e7cebSRobert Watson 	if (error) {
444310e7cebSRobert Watson 		SOCK_UNLOCK(so);
445c66b4d8dSRobert Watson 		return (error);
446310e7cebSRobert Watson 	}
447c66b4d8dSRobert Watson 
44830d239bcSRobert Watson 	mac_socket_relabel(cred, so, label);
449310e7cebSRobert Watson 	SOCK_UNLOCK(so);
450df3c68e4SRobert Watson 
451c66b4d8dSRobert Watson 	/*
452c66b4d8dSRobert Watson 	 * If the protocol has expressed interest in socket layer changes,
453df3c68e4SRobert Watson 	 * such as if it needs to propagate changes to a cached pcb label
454df3c68e4SRobert Watson 	 * from the socket, notify it of the label change while holding the
455df3c68e4SRobert Watson 	 * socket lock.
456c66b4d8dSRobert Watson 	 */
457c66b4d8dSRobert Watson 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
458c66b4d8dSRobert Watson 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
459c66b4d8dSRobert Watson 
460c66b4d8dSRobert Watson 	return (0);
461c66b4d8dSRobert Watson }
462c66b4d8dSRobert Watson 
463c66b4d8dSRobert Watson int
464c66b4d8dSRobert Watson mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
465c66b4d8dSRobert Watson {
466c66b4d8dSRobert Watson 	struct label *intlabel;
467c66b4d8dSRobert Watson 	char *buffer;
468c66b4d8dSRobert Watson 	int error;
469c66b4d8dSRobert Watson 
4706356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
4716356dba0SRobert Watson 		return (EINVAL);
4726356dba0SRobert Watson 
473c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
474c66b4d8dSRobert Watson 	if (error)
475c66b4d8dSRobert Watson 		return (error);
476c66b4d8dSRobert Watson 
477c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
478c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
479c66b4d8dSRobert Watson 	if (error) {
480c66b4d8dSRobert Watson 		free(buffer, M_MACTEMP);
481c66b4d8dSRobert Watson 		return (error);
482c66b4d8dSRobert Watson 	}
483c66b4d8dSRobert Watson 
484c66b4d8dSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
48530d239bcSRobert Watson 	error = mac_socket_internalize_label(intlabel, buffer);
486c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
487c66b4d8dSRobert Watson 	if (error)
488c66b4d8dSRobert Watson 		goto out;
489c66b4d8dSRobert Watson 
490c66b4d8dSRobert Watson 	error = mac_socket_label_set(cred, so, intlabel);
491c66b4d8dSRobert Watson out:
492c66b4d8dSRobert Watson 	mac_socket_label_free(intlabel);
493c66b4d8dSRobert Watson 	return (error);
494c66b4d8dSRobert Watson }
495c66b4d8dSRobert Watson 
496c66b4d8dSRobert Watson int
497c66b4d8dSRobert Watson mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
498c66b4d8dSRobert Watson {
499c66b4d8dSRobert Watson 	char *buffer, *elements;
500310e7cebSRobert Watson 	struct label *intlabel;
501c66b4d8dSRobert Watson 	int error;
502c66b4d8dSRobert Watson 
5036356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
5046356dba0SRobert Watson 		return (EINVAL);
5056356dba0SRobert Watson 
506c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
507c66b4d8dSRobert Watson 	if (error)
508c66b4d8dSRobert Watson 		return (error);
509c66b4d8dSRobert Watson 
510c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
511c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
512c66b4d8dSRobert Watson 	if (error) {
513c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
514c66b4d8dSRobert Watson 		return (error);
515c66b4d8dSRobert Watson 	}
516c66b4d8dSRobert Watson 
517c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
518310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
519310e7cebSRobert Watson 	SOCK_LOCK(so);
52030d239bcSRobert Watson 	mac_socket_copy_label(so->so_label, intlabel);
521310e7cebSRobert Watson 	SOCK_UNLOCK(so);
52230d239bcSRobert Watson 	error = mac_socket_externalize_label(intlabel, elements, buffer,
523310e7cebSRobert Watson 	    mac->m_buflen);
524310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
525c66b4d8dSRobert Watson 	if (error == 0)
526c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
527c66b4d8dSRobert Watson 
528c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
529c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
530c66b4d8dSRobert Watson 
531c66b4d8dSRobert Watson 	return (error);
532c66b4d8dSRobert Watson }
533c66b4d8dSRobert Watson 
534c66b4d8dSRobert Watson int
535c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
536c66b4d8dSRobert Watson     struct mac *mac)
537c66b4d8dSRobert Watson {
538c66b4d8dSRobert Watson 	char *elements, *buffer;
539310e7cebSRobert Watson 	struct label *intlabel;
540c66b4d8dSRobert Watson 	int error;
541c66b4d8dSRobert Watson 
5426356dba0SRobert Watson 	if (!(mac_labeled & MPC_OBJECT_SOCKET))
5436356dba0SRobert Watson 		return (EINVAL);
5446356dba0SRobert Watson 
545c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
546c66b4d8dSRobert Watson 	if (error)
547c66b4d8dSRobert Watson 		return (error);
548c66b4d8dSRobert Watson 
549c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
550c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
551c66b4d8dSRobert Watson 	if (error) {
552c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
553c66b4d8dSRobert Watson 		return (error);
554c66b4d8dSRobert Watson 	}
555c66b4d8dSRobert Watson 
556c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
557310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
558310e7cebSRobert Watson 	SOCK_LOCK(so);
55930d239bcSRobert Watson 	mac_socket_copy_label(so->so_peerlabel, intlabel);
560310e7cebSRobert Watson 	SOCK_UNLOCK(so);
56130d239bcSRobert Watson 	error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
562310e7cebSRobert Watson 	    mac->m_buflen);
563310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
564c66b4d8dSRobert Watson 	if (error == 0)
565c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
566c66b4d8dSRobert Watson 
567c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
568c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
569c66b4d8dSRobert Watson 
570c66b4d8dSRobert Watson 	return (error);
571c66b4d8dSRobert Watson }
572