xref: /freebsd/sys/security/mac/mac_socket.c (revision 6758f88ea476f8a5d8c956d2b4ab41a2c0aa6bd6)
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.
56758f88eSRobert Watson  * Copyright (c) 2005 SPARTA, Inc.
6c66b4d8dSRobert Watson  * All rights reserved.
7c66b4d8dSRobert Watson  *
8c66b4d8dSRobert Watson  * This software was developed by Robert Watson and Ilmar Habibulin for the
9c66b4d8dSRobert Watson  * TrustedBSD Project.
10c66b4d8dSRobert Watson  *
117f53207bSRobert Watson  * This software was developed for the FreeBSD Project in part by McAfee
127f53207bSRobert Watson  * Research, the Technology Research Division of Network Associates, Inc.
137f53207bSRobert Watson  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
147f53207bSRobert Watson  * DARPA CHATS research program.
15c66b4d8dSRobert Watson  *
166758f88eSRobert Watson  * This software was enhanced by SPARTA ISSO under SPAWAR contract
176758f88eSRobert Watson  * N66001-04-C-6019 ("SEFOS").
186758f88eSRobert Watson  *
19c66b4d8dSRobert Watson  * Redistribution and use in source and binary forms, with or without
20c66b4d8dSRobert Watson  * modification, are permitted provided that the following conditions
21c66b4d8dSRobert Watson  * are met:
22c66b4d8dSRobert Watson  * 1. Redistributions of source code must retain the above copyright
23c66b4d8dSRobert Watson  *    notice, this list of conditions and the following disclaimer.
24c66b4d8dSRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
25c66b4d8dSRobert Watson  *    notice, this list of conditions and the following disclaimer in the
26c66b4d8dSRobert Watson  *    documentation and/or other materials provided with the distribution.
27c66b4d8dSRobert Watson  *
28c66b4d8dSRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29c66b4d8dSRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30c66b4d8dSRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31c66b4d8dSRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32c66b4d8dSRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33c66b4d8dSRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34c66b4d8dSRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35c66b4d8dSRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36c66b4d8dSRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37c66b4d8dSRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38c66b4d8dSRobert Watson  * SUCH DAMAGE.
39c66b4d8dSRobert Watson  */
40c66b4d8dSRobert Watson 
41c66b4d8dSRobert Watson #include <sys/cdefs.h>
42c66b4d8dSRobert Watson __FBSDID("$FreeBSD$");
43c66b4d8dSRobert Watson 
44c66b4d8dSRobert Watson #include "opt_mac.h"
45c66b4d8dSRobert Watson 
46c66b4d8dSRobert Watson #include <sys/param.h>
47c66b4d8dSRobert Watson #include <sys/kernel.h>
48c66b4d8dSRobert Watson #include <sys/lock.h>
49c66b4d8dSRobert Watson #include <sys/malloc.h>
50c66b4d8dSRobert Watson #include <sys/mutex.h>
51c66b4d8dSRobert Watson #include <sys/mac.h>
52c66b4d8dSRobert Watson #include <sys/sbuf.h>
53c66b4d8dSRobert Watson #include <sys/systm.h>
54c66b4d8dSRobert Watson #include <sys/mount.h>
55c66b4d8dSRobert Watson #include <sys/file.h>
56c66b4d8dSRobert Watson #include <sys/namei.h>
57c66b4d8dSRobert Watson #include <sys/protosw.h>
58c66b4d8dSRobert Watson #include <sys/socket.h>
59c66b4d8dSRobert Watson #include <sys/socketvar.h>
60c66b4d8dSRobert Watson #include <sys/sysctl.h>
61c66b4d8dSRobert Watson 
62c66b4d8dSRobert Watson #include <sys/mac_policy.h>
63c66b4d8dSRobert Watson 
64c66b4d8dSRobert Watson #include <net/bpfdesc.h>
65c66b4d8dSRobert Watson #include <net/if.h>
66c66b4d8dSRobert Watson #include <net/if_var.h>
67c66b4d8dSRobert Watson 
68c66b4d8dSRobert Watson #include <netinet/in.h>
69c66b4d8dSRobert Watson #include <netinet/in_pcb.h>
70c66b4d8dSRobert Watson #include <netinet/ip_var.h>
71c66b4d8dSRobert Watson 
72c66b4d8dSRobert Watson #include <security/mac/mac_internal.h>
73c66b4d8dSRobert Watson 
74c66b4d8dSRobert Watson /*
75c66b4d8dSRobert Watson  * mac_enforce_socket is used by the inet code when delivering to an inpcb
76c66b4d8dSRobert Watson  * without hitting the socket layer, and has to be non-static for now.
77c66b4d8dSRobert Watson  */
78c66b4d8dSRobert Watson int	mac_enforce_socket = 1;
79c66b4d8dSRobert Watson SYSCTL_INT(_security_mac, OID_AUTO, enforce_socket, CTLFLAG_RW,
80c66b4d8dSRobert Watson     &mac_enforce_socket, 0, "Enforce MAC policy on socket operations");
81c66b4d8dSRobert Watson TUNABLE_INT("security.mac.enforce_socket", &mac_enforce_socket);
82c66b4d8dSRobert Watson 
83c66b4d8dSRobert Watson #ifdef MAC_DEBUG
84c66b4d8dSRobert Watson static unsigned int nmacsockets;
85c66b4d8dSRobert Watson 
86c66b4d8dSRobert Watson SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, sockets, CTLFLAG_RD,
87c66b4d8dSRobert Watson     &nmacsockets, 0, "number of sockets in use");
88c66b4d8dSRobert Watson #endif
89c66b4d8dSRobert Watson 
90c66b4d8dSRobert Watson struct label *
91c66b4d8dSRobert Watson mac_socket_label_alloc(int flag)
92c66b4d8dSRobert Watson {
93c66b4d8dSRobert Watson 	struct label *label;
94c66b4d8dSRobert Watson 	int error;
95c66b4d8dSRobert Watson 
96c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
97c66b4d8dSRobert Watson 	if (label == NULL)
98c66b4d8dSRobert Watson 		return (NULL);
99c66b4d8dSRobert Watson 
100c66b4d8dSRobert Watson 	MAC_CHECK(init_socket_label, label, flag);
101c66b4d8dSRobert Watson 	if (error) {
102c66b4d8dSRobert Watson 		MAC_PERFORM(destroy_socket_label, label);
103c66b4d8dSRobert Watson 		mac_labelzone_free(label);
104c66b4d8dSRobert Watson 		return (NULL);
105c66b4d8dSRobert Watson 	}
106c66b4d8dSRobert Watson 	MAC_DEBUG_COUNTER_INC(&nmacsockets);
107c66b4d8dSRobert Watson 	return (label);
108c66b4d8dSRobert Watson }
109c66b4d8dSRobert Watson 
110c66b4d8dSRobert Watson static struct label *
111c66b4d8dSRobert Watson mac_socket_peer_label_alloc(int flag)
112c66b4d8dSRobert Watson {
113c66b4d8dSRobert Watson 	struct label *label;
114c66b4d8dSRobert Watson 	int error;
115c66b4d8dSRobert Watson 
116c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
117c66b4d8dSRobert Watson 	if (label == NULL)
118c66b4d8dSRobert Watson 		return (NULL);
119c66b4d8dSRobert Watson 
120c66b4d8dSRobert Watson 	MAC_CHECK(init_socket_peer_label, label, flag);
121c66b4d8dSRobert Watson 	if (error) {
122c66b4d8dSRobert Watson 		MAC_PERFORM(destroy_socket_peer_label, label);
123c66b4d8dSRobert Watson 		mac_labelzone_free(label);
124c66b4d8dSRobert Watson 		return (NULL);
125c66b4d8dSRobert Watson 	}
126c66b4d8dSRobert Watson 	MAC_DEBUG_COUNTER_INC(&nmacsockets);
127c66b4d8dSRobert Watson 	return (label);
128c66b4d8dSRobert Watson }
129c66b4d8dSRobert Watson 
130c66b4d8dSRobert Watson int
131c66b4d8dSRobert Watson mac_init_socket(struct socket *so, int flag)
132c66b4d8dSRobert Watson {
133c66b4d8dSRobert Watson 
134c66b4d8dSRobert Watson 	so->so_label = mac_socket_label_alloc(flag);
135c66b4d8dSRobert Watson 	if (so->so_label == NULL)
136c66b4d8dSRobert Watson 		return (ENOMEM);
137c66b4d8dSRobert Watson 	so->so_peerlabel = mac_socket_peer_label_alloc(flag);
138c66b4d8dSRobert Watson 	if (so->so_peerlabel == NULL) {
139c66b4d8dSRobert Watson 		mac_socket_label_free(so->so_label);
140c66b4d8dSRobert Watson 		so->so_label = NULL;
141c66b4d8dSRobert Watson 		return (ENOMEM);
142c66b4d8dSRobert Watson 	}
143c66b4d8dSRobert Watson 	return (0);
144c66b4d8dSRobert Watson }
145c66b4d8dSRobert Watson 
146c66b4d8dSRobert Watson void
147c66b4d8dSRobert Watson mac_socket_label_free(struct label *label)
148c66b4d8dSRobert Watson {
149c66b4d8dSRobert Watson 
150c66b4d8dSRobert Watson 	MAC_PERFORM(destroy_socket_label, label);
151c66b4d8dSRobert Watson 	mac_labelzone_free(label);
152c66b4d8dSRobert Watson 	MAC_DEBUG_COUNTER_DEC(&nmacsockets);
153c66b4d8dSRobert Watson }
154c66b4d8dSRobert Watson 
155c66b4d8dSRobert Watson static void
156c66b4d8dSRobert Watson mac_socket_peer_label_free(struct label *label)
157c66b4d8dSRobert Watson {
158c66b4d8dSRobert Watson 
159c66b4d8dSRobert Watson 	MAC_PERFORM(destroy_socket_peer_label, label);
160c66b4d8dSRobert Watson 	mac_labelzone_free(label);
161c66b4d8dSRobert Watson 	MAC_DEBUG_COUNTER_DEC(&nmacsockets);
162c66b4d8dSRobert Watson }
163c66b4d8dSRobert Watson 
164c66b4d8dSRobert Watson void
165c66b4d8dSRobert Watson mac_destroy_socket(struct socket *socket)
166c66b4d8dSRobert Watson {
167c66b4d8dSRobert Watson 
168c66b4d8dSRobert Watson 	mac_socket_label_free(socket->so_label);
169c66b4d8dSRobert Watson 	socket->so_label = NULL;
170c66b4d8dSRobert Watson 	mac_socket_peer_label_free(socket->so_peerlabel);
171c66b4d8dSRobert Watson 	socket->so_peerlabel = NULL;
172c66b4d8dSRobert Watson }
173c66b4d8dSRobert Watson 
174c66b4d8dSRobert Watson void
175c66b4d8dSRobert Watson mac_copy_socket_label(struct label *src, struct label *dest)
176c66b4d8dSRobert Watson {
177c66b4d8dSRobert Watson 
178c66b4d8dSRobert Watson 	MAC_PERFORM(copy_socket_label, src, dest);
179c66b4d8dSRobert Watson }
180c66b4d8dSRobert Watson 
181c66b4d8dSRobert Watson int
182c66b4d8dSRobert Watson mac_externalize_socket_label(struct label *label, char *elements,
183c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
184c66b4d8dSRobert Watson {
185c66b4d8dSRobert Watson 	int error;
186c66b4d8dSRobert Watson 
187c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
188c66b4d8dSRobert Watson 
189c66b4d8dSRobert Watson 	return (error);
190c66b4d8dSRobert Watson }
191c66b4d8dSRobert Watson 
192c66b4d8dSRobert Watson static int
193c66b4d8dSRobert Watson mac_externalize_socket_peer_label(struct label *label, char *elements,
194c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
195c66b4d8dSRobert Watson {
196c66b4d8dSRobert Watson 	int error;
197c66b4d8dSRobert Watson 
198c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket_peer, label, elements, outbuf, outbuflen);
199c66b4d8dSRobert Watson 
200c66b4d8dSRobert Watson 	return (error);
201c66b4d8dSRobert Watson }
202c66b4d8dSRobert Watson 
203c66b4d8dSRobert Watson int
204c66b4d8dSRobert Watson mac_internalize_socket_label(struct label *label, char *string)
205c66b4d8dSRobert Watson {
206c66b4d8dSRobert Watson 	int error;
207c66b4d8dSRobert Watson 
208c66b4d8dSRobert Watson 	MAC_INTERNALIZE(socket, label, string);
209c66b4d8dSRobert Watson 
210c66b4d8dSRobert Watson 	return (error);
211c66b4d8dSRobert Watson }
212c66b4d8dSRobert Watson 
213c66b4d8dSRobert Watson void
214c66b4d8dSRobert Watson mac_create_socket(struct ucred *cred, struct socket *socket)
215c66b4d8dSRobert Watson {
216c66b4d8dSRobert Watson 
217c66b4d8dSRobert Watson 	MAC_PERFORM(create_socket, cred, socket, socket->so_label);
218c66b4d8dSRobert Watson }
219c66b4d8dSRobert Watson 
220c66b4d8dSRobert Watson void
221c66b4d8dSRobert Watson mac_create_socket_from_socket(struct socket *oldsocket,
222c66b4d8dSRobert Watson     struct socket *newsocket)
223c66b4d8dSRobert Watson {
224c66b4d8dSRobert Watson 
225310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(oldsocket);
226c66b4d8dSRobert Watson 	MAC_PERFORM(create_socket_from_socket, oldsocket, oldsocket->so_label,
227c66b4d8dSRobert Watson 	    newsocket, newsocket->so_label);
228c66b4d8dSRobert Watson }
229c66b4d8dSRobert Watson 
230c66b4d8dSRobert Watson static void
231c66b4d8dSRobert Watson mac_relabel_socket(struct ucred *cred, struct socket *socket,
232c66b4d8dSRobert Watson     struct label *newlabel)
233c66b4d8dSRobert Watson {
234c66b4d8dSRobert Watson 
235310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
236c66b4d8dSRobert Watson 	MAC_PERFORM(relabel_socket, cred, socket, socket->so_label, newlabel);
237c66b4d8dSRobert Watson }
238c66b4d8dSRobert Watson 
239c66b4d8dSRobert Watson void
240c66b4d8dSRobert Watson mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket)
241c66b4d8dSRobert Watson {
242c66b4d8dSRobert Watson 	struct label *label;
243c66b4d8dSRobert Watson 
244310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
245310e7cebSRobert Watson 
246c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
247c66b4d8dSRobert Watson 
248c66b4d8dSRobert Watson 	MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, label, socket,
249c66b4d8dSRobert Watson 	    socket->so_peerlabel);
250c66b4d8dSRobert Watson }
251c66b4d8dSRobert Watson 
252c66b4d8dSRobert Watson void
253c66b4d8dSRobert Watson mac_set_socket_peer_from_socket(struct socket *oldsocket,
254c66b4d8dSRobert Watson     struct socket *newsocket)
255c66b4d8dSRobert Watson {
256c66b4d8dSRobert Watson 
257310e7cebSRobert Watson 	/*
258310e7cebSRobert Watson 	 * XXXRW: only hold the socket lock on one at a time, as one
259310e7cebSRobert Watson 	 * socket is the original, and one is the new.  However, it's
260310e7cebSRobert Watson 	 * called in both directions, so we can't assert the lock
261310e7cebSRobert Watson 	 * here currently.
262310e7cebSRobert Watson 	 */
263c66b4d8dSRobert Watson 	MAC_PERFORM(set_socket_peer_from_socket, oldsocket,
264c66b4d8dSRobert Watson 	    oldsocket->so_label, newsocket, newsocket->so_peerlabel);
265c66b4d8dSRobert Watson }
266c66b4d8dSRobert Watson 
267c66b4d8dSRobert Watson void
268c66b4d8dSRobert Watson mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf)
269c66b4d8dSRobert Watson {
270c66b4d8dSRobert Watson 	struct label *label;
271c66b4d8dSRobert Watson 
272c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
273c66b4d8dSRobert Watson 
274310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
275c66b4d8dSRobert Watson 	MAC_PERFORM(create_mbuf_from_socket, socket, socket->so_label, mbuf,
276c66b4d8dSRobert Watson 	    label);
277c66b4d8dSRobert Watson }
278c66b4d8dSRobert Watson 
279c66b4d8dSRobert Watson int
2807f53207bSRobert Watson mac_check_socket_accept(struct ucred *cred, struct socket *socket)
2817f53207bSRobert Watson {
2827f53207bSRobert Watson 	int error;
2837f53207bSRobert Watson 
2847f53207bSRobert Watson 	SOCK_LOCK_ASSERT(socket);
2857f53207bSRobert Watson 
2867f53207bSRobert Watson 	if (!mac_enforce_socket)
2877f53207bSRobert Watson 		return (0);
2887f53207bSRobert Watson 
2897f53207bSRobert Watson 	MAC_CHECK(check_socket_accept, cred, socket, socket->so_label);
2907f53207bSRobert Watson 
2917f53207bSRobert Watson 	return (error);
2927f53207bSRobert Watson }
2937f53207bSRobert Watson 
2947f53207bSRobert Watson int
295c66b4d8dSRobert Watson mac_check_socket_bind(struct ucred *ucred, struct socket *socket,
296c66b4d8dSRobert Watson     struct sockaddr *sockaddr)
297c66b4d8dSRobert Watson {
298c66b4d8dSRobert Watson 	int error;
299c66b4d8dSRobert Watson 
300310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
301310e7cebSRobert Watson 
302c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
303c66b4d8dSRobert Watson 		return (0);
304c66b4d8dSRobert Watson 
305c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_bind, ucred, socket, socket->so_label,
306c66b4d8dSRobert Watson 	    sockaddr);
307c66b4d8dSRobert Watson 
308c66b4d8dSRobert Watson 	return (error);
309c66b4d8dSRobert Watson }
310c66b4d8dSRobert Watson 
311c66b4d8dSRobert Watson int
312c66b4d8dSRobert Watson mac_check_socket_connect(struct ucred *cred, struct socket *socket,
313c66b4d8dSRobert Watson     struct sockaddr *sockaddr)
314c66b4d8dSRobert Watson {
315c66b4d8dSRobert Watson 	int error;
316c66b4d8dSRobert Watson 
317310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
318310e7cebSRobert Watson 
319c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
320c66b4d8dSRobert Watson 		return (0);
321c66b4d8dSRobert Watson 
322c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_connect, cred, socket, socket->so_label,
323c66b4d8dSRobert Watson 	    sockaddr);
324c66b4d8dSRobert Watson 
325c66b4d8dSRobert Watson 	return (error);
326c66b4d8dSRobert Watson }
327c66b4d8dSRobert Watson 
328c66b4d8dSRobert Watson int
3296758f88eSRobert Watson mac_check_socket_create(struct ucred *cred, int domain, int type,
3306758f88eSRobert Watson     int protocol)
3316758f88eSRobert Watson {
3326758f88eSRobert Watson 	int error;
3336758f88eSRobert Watson 
3346758f88eSRobert Watson 	if (!mac_enforce_socket)
3356758f88eSRobert Watson 		return (0);
3366758f88eSRobert Watson 
3376758f88eSRobert Watson 	MAC_CHECK(check_socket_create, cred, domain, type, protocol);
3386758f88eSRobert Watson 
3396758f88eSRobert Watson 	return (error);
3406758f88eSRobert Watson }
3416758f88eSRobert Watson 
3426758f88eSRobert Watson int
343c66b4d8dSRobert Watson mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf)
344c66b4d8dSRobert Watson {
345c66b4d8dSRobert Watson 	struct label *label;
346c66b4d8dSRobert Watson 	int error;
347c66b4d8dSRobert Watson 
348310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
349310e7cebSRobert Watson 
350c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
351c66b4d8dSRobert Watson 		return (0);
352c66b4d8dSRobert Watson 
353c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
354c66b4d8dSRobert Watson 
355c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_deliver, socket, socket->so_label, mbuf,
356c66b4d8dSRobert Watson 	    label);
357c66b4d8dSRobert Watson 
358c66b4d8dSRobert Watson 	return (error);
359c66b4d8dSRobert Watson }
360c66b4d8dSRobert Watson 
361c66b4d8dSRobert Watson int
362c66b4d8dSRobert Watson mac_check_socket_listen(struct ucred *cred, struct socket *socket)
363c66b4d8dSRobert Watson {
364c66b4d8dSRobert Watson 	int error;
365c66b4d8dSRobert Watson 
366310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
367310e7cebSRobert Watson 
368c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
369c66b4d8dSRobert Watson 		return (0);
370c66b4d8dSRobert Watson 
371c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_listen, cred, socket, socket->so_label);
372c66b4d8dSRobert Watson 	return (error);
373c66b4d8dSRobert Watson }
374c66b4d8dSRobert Watson 
375c66b4d8dSRobert Watson int
3767f53207bSRobert Watson mac_check_socket_poll(struct ucred *cred, struct socket *so)
3777f53207bSRobert Watson {
3787f53207bSRobert Watson 	int error;
3797f53207bSRobert Watson 
3807f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
3817f53207bSRobert Watson 
3827f53207bSRobert Watson 	if (!mac_enforce_socket)
3837f53207bSRobert Watson 		return (0);
3847f53207bSRobert Watson 
3857f53207bSRobert Watson 	MAC_CHECK(check_socket_poll, cred, so, so->so_label);
3867f53207bSRobert Watson 	return (error);
3877f53207bSRobert Watson }
3887f53207bSRobert Watson 
3897f53207bSRobert Watson int
390c66b4d8dSRobert Watson mac_check_socket_receive(struct ucred *cred, struct socket *so)
391c66b4d8dSRobert Watson {
392c66b4d8dSRobert Watson 	int error;
393c66b4d8dSRobert Watson 
394310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
395310e7cebSRobert Watson 
396c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
397c66b4d8dSRobert Watson 		return (0);
398c66b4d8dSRobert Watson 
399c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_receive, cred, so, so->so_label);
400c66b4d8dSRobert Watson 
401c66b4d8dSRobert Watson 	return (error);
402c66b4d8dSRobert Watson }
403c66b4d8dSRobert Watson 
404c66b4d8dSRobert Watson static int
405c66b4d8dSRobert Watson mac_check_socket_relabel(struct ucred *cred, struct socket *socket,
406c66b4d8dSRobert Watson     struct label *newlabel)
407c66b4d8dSRobert Watson {
408c66b4d8dSRobert Watson 	int error;
409c66b4d8dSRobert Watson 
410310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
411310e7cebSRobert Watson 
412c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_relabel, cred, socket, socket->so_label,
413c66b4d8dSRobert Watson 	    newlabel);
414c66b4d8dSRobert Watson 
415c66b4d8dSRobert Watson 	return (error);
416c66b4d8dSRobert Watson }
417c66b4d8dSRobert Watson 
418c66b4d8dSRobert Watson int
419c66b4d8dSRobert Watson mac_check_socket_send(struct ucred *cred, struct socket *so)
420c66b4d8dSRobert Watson {
421c66b4d8dSRobert Watson 	int error;
422c66b4d8dSRobert Watson 
423310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
424310e7cebSRobert Watson 
425c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
426c66b4d8dSRobert Watson 		return (0);
427c66b4d8dSRobert Watson 
428c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_send, cred, so, so->so_label);
429c66b4d8dSRobert Watson 
430c66b4d8dSRobert Watson 	return (error);
431c66b4d8dSRobert Watson }
432c66b4d8dSRobert Watson 
433c66b4d8dSRobert Watson int
4347f53207bSRobert Watson mac_check_socket_stat(struct ucred *cred, struct socket *so)
4357f53207bSRobert Watson {
4367f53207bSRobert Watson 	int error;
4377f53207bSRobert Watson 
4387f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
4397f53207bSRobert Watson 
4407f53207bSRobert Watson 	if (!mac_enforce_socket)
4417f53207bSRobert Watson 		return (0);
4427f53207bSRobert Watson 
4437f53207bSRobert Watson 	MAC_CHECK(check_socket_stat, cred, so, so->so_label);
4447f53207bSRobert Watson 
4457f53207bSRobert Watson 	return (error);
4467f53207bSRobert Watson }
4477f53207bSRobert Watson 
4487f53207bSRobert Watson int
449c66b4d8dSRobert Watson mac_check_socket_visible(struct ucred *cred, struct socket *socket)
450c66b4d8dSRobert Watson {
451c66b4d8dSRobert Watson 	int error;
452c66b4d8dSRobert Watson 
453310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
454310e7cebSRobert Watson 
455c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
456c66b4d8dSRobert Watson 		return (0);
457c66b4d8dSRobert Watson 
458c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_visible, cred, socket, socket->so_label);
459c66b4d8dSRobert Watson 
460c66b4d8dSRobert Watson 	return (error);
461c66b4d8dSRobert Watson }
462c66b4d8dSRobert Watson 
463c66b4d8dSRobert Watson int
464c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so,
465c66b4d8dSRobert Watson     struct label *label)
466c66b4d8dSRobert Watson {
467c66b4d8dSRobert Watson 	int error;
468c66b4d8dSRobert Watson 
469310e7cebSRobert Watson 	/*
470310e7cebSRobert Watson 	 * We acquire the socket lock when we perform the test and set,
471310e7cebSRobert Watson 	 * but have to release it as the pcb code needs to acquire the
472310e7cebSRobert Watson 	 * pcb lock, which will precede the socket lock in the lock
473310e7cebSRobert Watson 	 * order.  However, this is fine, as any race will simply
474310e7cebSRobert Watson 	 * result in the inpcb being refreshed twice, but still
475310e7cebSRobert Watson 	 * consistently, as the inpcb code will acquire the socket lock
476310e7cebSRobert Watson 	 * before refreshing, holding both locks.
477310e7cebSRobert Watson 	 */
478310e7cebSRobert Watson 	SOCK_LOCK(so);
479c66b4d8dSRobert Watson 	error = mac_check_socket_relabel(cred, so, label);
480310e7cebSRobert Watson 	if (error) {
481310e7cebSRobert Watson 		SOCK_UNLOCK(so);
482c66b4d8dSRobert Watson 		return (error);
483310e7cebSRobert Watson 	}
484c66b4d8dSRobert Watson 
485c66b4d8dSRobert Watson 	mac_relabel_socket(cred, so, label);
486310e7cebSRobert Watson 	SOCK_UNLOCK(so);
487c66b4d8dSRobert Watson 	/*
488c66b4d8dSRobert Watson 	 * If the protocol has expressed interest in socket layer changes,
489c66b4d8dSRobert Watson 	 * such as if it needs to propagate changes to a cached pcb
490c66b4d8dSRobert Watson 	 * label from the socket, notify it of the label change while
491c66b4d8dSRobert Watson 	 * holding the socket lock.
492c66b4d8dSRobert Watson 	 */
493c66b4d8dSRobert Watson 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
494c66b4d8dSRobert Watson 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
495c66b4d8dSRobert Watson 
496c66b4d8dSRobert Watson 	return (0);
497c66b4d8dSRobert Watson }
498c66b4d8dSRobert Watson 
499c66b4d8dSRobert Watson int
500c66b4d8dSRobert Watson mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
501c66b4d8dSRobert Watson {
502c66b4d8dSRobert Watson 	struct label *intlabel;
503c66b4d8dSRobert Watson 	char *buffer;
504c66b4d8dSRobert Watson 	int error;
505c66b4d8dSRobert Watson 
506c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
507c66b4d8dSRobert Watson 	if (error)
508c66b4d8dSRobert Watson 		return (error);
509c66b4d8dSRobert Watson 
510c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
511c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
512c66b4d8dSRobert Watson 	if (error) {
513c66b4d8dSRobert Watson 		free(buffer, M_MACTEMP);
514c66b4d8dSRobert Watson 		return (error);
515c66b4d8dSRobert Watson 	}
516c66b4d8dSRobert Watson 
517c66b4d8dSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
518c66b4d8dSRobert Watson 	error = mac_internalize_socket_label(intlabel, buffer);
519c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
520c66b4d8dSRobert Watson 	if (error)
521c66b4d8dSRobert Watson 		goto out;
522c66b4d8dSRobert Watson 
523c66b4d8dSRobert Watson 	error = mac_socket_label_set(cred, so, intlabel);
524c66b4d8dSRobert Watson out:
525c66b4d8dSRobert Watson 	mac_socket_label_free(intlabel);
526c66b4d8dSRobert Watson 	return (error);
527c66b4d8dSRobert Watson }
528c66b4d8dSRobert Watson 
529c66b4d8dSRobert Watson int
530c66b4d8dSRobert Watson mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
531c66b4d8dSRobert Watson {
532c66b4d8dSRobert Watson 	char *buffer, *elements;
533310e7cebSRobert Watson 	struct label *intlabel;
534c66b4d8dSRobert Watson 	int error;
535c66b4d8dSRobert Watson 
536c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
537c66b4d8dSRobert Watson 	if (error)
538c66b4d8dSRobert Watson 		return (error);
539c66b4d8dSRobert Watson 
540c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
541c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
542c66b4d8dSRobert Watson 	if (error) {
543c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
544c66b4d8dSRobert Watson 		return (error);
545c66b4d8dSRobert Watson 	}
546c66b4d8dSRobert Watson 
547c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
548310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
549310e7cebSRobert Watson 	SOCK_LOCK(so);
550310e7cebSRobert Watson 	mac_copy_socket_label(so->so_label, intlabel);
551310e7cebSRobert Watson 	SOCK_UNLOCK(so);
552310e7cebSRobert Watson 	error = mac_externalize_socket_label(intlabel, elements, buffer,
553310e7cebSRobert Watson 	    mac->m_buflen);
554310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
555c66b4d8dSRobert Watson 	if (error == 0)
556c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
557c66b4d8dSRobert Watson 
558c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
559c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
560c66b4d8dSRobert Watson 
561c66b4d8dSRobert Watson 	return (error);
562c66b4d8dSRobert Watson }
563c66b4d8dSRobert Watson 
564c66b4d8dSRobert Watson int
565c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
566c66b4d8dSRobert Watson     struct mac *mac)
567c66b4d8dSRobert Watson {
568c66b4d8dSRobert Watson 	char *elements, *buffer;
569310e7cebSRobert Watson 	struct label *intlabel;
570c66b4d8dSRobert Watson 	int error;
571c66b4d8dSRobert Watson 
572c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
573c66b4d8dSRobert Watson 	if (error)
574c66b4d8dSRobert Watson 		return (error);
575c66b4d8dSRobert Watson 
576c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
577c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
578c66b4d8dSRobert Watson 	if (error) {
579c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
580c66b4d8dSRobert Watson 		return (error);
581c66b4d8dSRobert Watson 	}
582c66b4d8dSRobert Watson 
583c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
584310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
585310e7cebSRobert Watson 	SOCK_LOCK(so);
586310e7cebSRobert Watson 	mac_copy_socket_label(so->so_peerlabel, intlabel);
587310e7cebSRobert Watson 	SOCK_UNLOCK(so);
588310e7cebSRobert Watson 	error = mac_externalize_socket_peer_label(intlabel, elements, buffer,
589310e7cebSRobert Watson 	    mac->m_buflen);
590310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
591c66b4d8dSRobert Watson 	if (error == 0)
592c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
593c66b4d8dSRobert Watson 
594c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
595c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
596c66b4d8dSRobert Watson 
597c66b4d8dSRobert Watson 	return (error);
598c66b4d8dSRobert Watson }
599