xref: /freebsd/sys/security/mac/mac_socket.c (revision 310e7ceb94990acce70c4a1230d0f397aaf93555)
1c66b4d8dSRobert Watson /*-
2c66b4d8dSRobert Watson  * Copyright (c) 1999-2002 Robert N. M. Watson
3c66b4d8dSRobert Watson  * Copyright (c) 2001 Ilmar S. Habibulin
4c66b4d8dSRobert Watson  * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
5c66b4d8dSRobert Watson  * All rights reserved.
6c66b4d8dSRobert Watson  *
7c66b4d8dSRobert Watson  * This software was developed by Robert Watson and Ilmar Habibulin for the
8c66b4d8dSRobert Watson  * TrustedBSD Project.
9c66b4d8dSRobert Watson  *
10c66b4d8dSRobert Watson  * This software was developed for the FreeBSD Project in part by Network
11c66b4d8dSRobert Watson  * Associates Laboratories, the Security Research Division of Network
12c66b4d8dSRobert Watson  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13c66b4d8dSRobert Watson  * as part of the DARPA CHATS research program.
14c66b4d8dSRobert Watson  *
15c66b4d8dSRobert Watson  * Redistribution and use in source and binary forms, with or without
16c66b4d8dSRobert Watson  * modification, are permitted provided that the following conditions
17c66b4d8dSRobert Watson  * are met:
18c66b4d8dSRobert Watson  * 1. Redistributions of source code must retain the above copyright
19c66b4d8dSRobert Watson  *    notice, this list of conditions and the following disclaimer.
20c66b4d8dSRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
21c66b4d8dSRobert Watson  *    notice, this list of conditions and the following disclaimer in the
22c66b4d8dSRobert Watson  *    documentation and/or other materials provided with the distribution.
23c66b4d8dSRobert Watson  *
24c66b4d8dSRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25c66b4d8dSRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26c66b4d8dSRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27c66b4d8dSRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28c66b4d8dSRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29c66b4d8dSRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30c66b4d8dSRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31c66b4d8dSRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32c66b4d8dSRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33c66b4d8dSRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34c66b4d8dSRobert Watson  * SUCH DAMAGE.
35c66b4d8dSRobert Watson  */
36c66b4d8dSRobert Watson 
37c66b4d8dSRobert Watson #include <sys/cdefs.h>
38c66b4d8dSRobert Watson __FBSDID("$FreeBSD$");
39c66b4d8dSRobert Watson 
40c66b4d8dSRobert Watson #include "opt_mac.h"
41c66b4d8dSRobert Watson 
42c66b4d8dSRobert Watson #include <sys/param.h>
43c66b4d8dSRobert Watson #include <sys/kernel.h>
44c66b4d8dSRobert Watson #include <sys/lock.h>
45c66b4d8dSRobert Watson #include <sys/malloc.h>
46c66b4d8dSRobert Watson #include <sys/mutex.h>
47c66b4d8dSRobert Watson #include <sys/mac.h>
48c66b4d8dSRobert Watson #include <sys/sbuf.h>
49c66b4d8dSRobert Watson #include <sys/systm.h>
50c66b4d8dSRobert Watson #include <sys/mount.h>
51c66b4d8dSRobert Watson #include <sys/file.h>
52c66b4d8dSRobert Watson #include <sys/namei.h>
53c66b4d8dSRobert Watson #include <sys/protosw.h>
54c66b4d8dSRobert Watson #include <sys/socket.h>
55c66b4d8dSRobert Watson #include <sys/socketvar.h>
56c66b4d8dSRobert Watson #include <sys/sysctl.h>
57c66b4d8dSRobert Watson 
58c66b4d8dSRobert Watson #include <sys/mac_policy.h>
59c66b4d8dSRobert Watson 
60c66b4d8dSRobert Watson #include <net/bpfdesc.h>
61c66b4d8dSRobert Watson #include <net/if.h>
62c66b4d8dSRobert Watson #include <net/if_var.h>
63c66b4d8dSRobert Watson 
64c66b4d8dSRobert Watson #include <netinet/in.h>
65c66b4d8dSRobert Watson #include <netinet/in_pcb.h>
66c66b4d8dSRobert Watson #include <netinet/ip_var.h>
67c66b4d8dSRobert Watson 
68c66b4d8dSRobert Watson #include <security/mac/mac_internal.h>
69c66b4d8dSRobert Watson 
70c66b4d8dSRobert Watson /*
71c66b4d8dSRobert Watson  * mac_enforce_socket is used by the inet code when delivering to an inpcb
72c66b4d8dSRobert Watson  * without hitting the socket layer, and has to be non-static for now.
73c66b4d8dSRobert Watson  */
74c66b4d8dSRobert Watson int	mac_enforce_socket = 1;
75c66b4d8dSRobert Watson SYSCTL_INT(_security_mac, OID_AUTO, enforce_socket, CTLFLAG_RW,
76c66b4d8dSRobert Watson     &mac_enforce_socket, 0, "Enforce MAC policy on socket operations");
77c66b4d8dSRobert Watson TUNABLE_INT("security.mac.enforce_socket", &mac_enforce_socket);
78c66b4d8dSRobert Watson 
79c66b4d8dSRobert Watson #ifdef MAC_DEBUG
80c66b4d8dSRobert Watson static unsigned int nmacsockets;
81c66b4d8dSRobert Watson 
82c66b4d8dSRobert Watson SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, sockets, CTLFLAG_RD,
83c66b4d8dSRobert Watson     &nmacsockets, 0, "number of sockets in use");
84c66b4d8dSRobert Watson #endif
85c66b4d8dSRobert Watson 
86c66b4d8dSRobert Watson struct label *
87c66b4d8dSRobert Watson mac_socket_label_alloc(int flag)
88c66b4d8dSRobert Watson {
89c66b4d8dSRobert Watson 	struct label *label;
90c66b4d8dSRobert Watson 	int error;
91c66b4d8dSRobert Watson 
92c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
93c66b4d8dSRobert Watson 	if (label == NULL)
94c66b4d8dSRobert Watson 		return (NULL);
95c66b4d8dSRobert Watson 
96c66b4d8dSRobert Watson 	MAC_CHECK(init_socket_label, label, flag);
97c66b4d8dSRobert Watson 	if (error) {
98c66b4d8dSRobert Watson 		MAC_PERFORM(destroy_socket_label, label);
99c66b4d8dSRobert Watson 		mac_labelzone_free(label);
100c66b4d8dSRobert Watson 		return (NULL);
101c66b4d8dSRobert Watson 	}
102c66b4d8dSRobert Watson 	MAC_DEBUG_COUNTER_INC(&nmacsockets);
103c66b4d8dSRobert Watson 	return (label);
104c66b4d8dSRobert Watson }
105c66b4d8dSRobert Watson 
106c66b4d8dSRobert Watson static struct label *
107c66b4d8dSRobert Watson mac_socket_peer_label_alloc(int flag)
108c66b4d8dSRobert Watson {
109c66b4d8dSRobert Watson 	struct label *label;
110c66b4d8dSRobert Watson 	int error;
111c66b4d8dSRobert Watson 
112c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
113c66b4d8dSRobert Watson 	if (label == NULL)
114c66b4d8dSRobert Watson 		return (NULL);
115c66b4d8dSRobert Watson 
116c66b4d8dSRobert Watson 	MAC_CHECK(init_socket_peer_label, label, flag);
117c66b4d8dSRobert Watson 	if (error) {
118c66b4d8dSRobert Watson 		MAC_PERFORM(destroy_socket_peer_label, label);
119c66b4d8dSRobert Watson 		mac_labelzone_free(label);
120c66b4d8dSRobert Watson 		return (NULL);
121c66b4d8dSRobert Watson 	}
122c66b4d8dSRobert Watson 	MAC_DEBUG_COUNTER_INC(&nmacsockets);
123c66b4d8dSRobert Watson 	return (label);
124c66b4d8dSRobert Watson }
125c66b4d8dSRobert Watson 
126c66b4d8dSRobert Watson int
127c66b4d8dSRobert Watson mac_init_socket(struct socket *so, int flag)
128c66b4d8dSRobert Watson {
129c66b4d8dSRobert Watson 
130c66b4d8dSRobert Watson 	so->so_label = mac_socket_label_alloc(flag);
131c66b4d8dSRobert Watson 	if (so->so_label == NULL)
132c66b4d8dSRobert Watson 		return (ENOMEM);
133c66b4d8dSRobert Watson 	so->so_peerlabel = mac_socket_peer_label_alloc(flag);
134c66b4d8dSRobert Watson 	if (so->so_peerlabel == NULL) {
135c66b4d8dSRobert Watson 		mac_socket_label_free(so->so_label);
136c66b4d8dSRobert Watson 		so->so_label = NULL;
137c66b4d8dSRobert Watson 		return (ENOMEM);
138c66b4d8dSRobert Watson 	}
139c66b4d8dSRobert Watson 	return (0);
140c66b4d8dSRobert Watson }
141c66b4d8dSRobert Watson 
142c66b4d8dSRobert Watson void
143c66b4d8dSRobert Watson mac_socket_label_free(struct label *label)
144c66b4d8dSRobert Watson {
145c66b4d8dSRobert Watson 
146c66b4d8dSRobert Watson 	MAC_PERFORM(destroy_socket_label, label);
147c66b4d8dSRobert Watson 	mac_labelzone_free(label);
148c66b4d8dSRobert Watson 	MAC_DEBUG_COUNTER_DEC(&nmacsockets);
149c66b4d8dSRobert Watson }
150c66b4d8dSRobert Watson 
151c66b4d8dSRobert Watson static void
152c66b4d8dSRobert Watson mac_socket_peer_label_free(struct label *label)
153c66b4d8dSRobert Watson {
154c66b4d8dSRobert Watson 
155c66b4d8dSRobert Watson 	MAC_PERFORM(destroy_socket_peer_label, label);
156c66b4d8dSRobert Watson 	mac_labelzone_free(label);
157c66b4d8dSRobert Watson 	MAC_DEBUG_COUNTER_DEC(&nmacsockets);
158c66b4d8dSRobert Watson }
159c66b4d8dSRobert Watson 
160c66b4d8dSRobert Watson void
161c66b4d8dSRobert Watson mac_destroy_socket(struct socket *socket)
162c66b4d8dSRobert Watson {
163c66b4d8dSRobert Watson 
164c66b4d8dSRobert Watson 	mac_socket_label_free(socket->so_label);
165c66b4d8dSRobert Watson 	socket->so_label = NULL;
166c66b4d8dSRobert Watson 	mac_socket_peer_label_free(socket->so_peerlabel);
167c66b4d8dSRobert Watson 	socket->so_peerlabel = NULL;
168c66b4d8dSRobert Watson }
169c66b4d8dSRobert Watson 
170c66b4d8dSRobert Watson void
171c66b4d8dSRobert Watson mac_copy_socket_label(struct label *src, struct label *dest)
172c66b4d8dSRobert Watson {
173c66b4d8dSRobert Watson 
174c66b4d8dSRobert Watson 	MAC_PERFORM(copy_socket_label, src, dest);
175c66b4d8dSRobert Watson }
176c66b4d8dSRobert Watson 
177c66b4d8dSRobert Watson int
178c66b4d8dSRobert Watson mac_externalize_socket_label(struct label *label, char *elements,
179c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
180c66b4d8dSRobert Watson {
181c66b4d8dSRobert Watson 	int error;
182c66b4d8dSRobert Watson 
183c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
184c66b4d8dSRobert Watson 
185c66b4d8dSRobert Watson 	return (error);
186c66b4d8dSRobert Watson }
187c66b4d8dSRobert Watson 
188c66b4d8dSRobert Watson static int
189c66b4d8dSRobert Watson mac_externalize_socket_peer_label(struct label *label, char *elements,
190c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
191c66b4d8dSRobert Watson {
192c66b4d8dSRobert Watson 	int error;
193c66b4d8dSRobert Watson 
194c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket_peer, label, elements, outbuf, outbuflen);
195c66b4d8dSRobert Watson 
196c66b4d8dSRobert Watson 	return (error);
197c66b4d8dSRobert Watson }
198c66b4d8dSRobert Watson 
199c66b4d8dSRobert Watson int
200c66b4d8dSRobert Watson mac_internalize_socket_label(struct label *label, char *string)
201c66b4d8dSRobert Watson {
202c66b4d8dSRobert Watson 	int error;
203c66b4d8dSRobert Watson 
204c66b4d8dSRobert Watson 	MAC_INTERNALIZE(socket, label, string);
205c66b4d8dSRobert Watson 
206c66b4d8dSRobert Watson 	return (error);
207c66b4d8dSRobert Watson }
208c66b4d8dSRobert Watson 
209c66b4d8dSRobert Watson void
210c66b4d8dSRobert Watson mac_create_socket(struct ucred *cred, struct socket *socket)
211c66b4d8dSRobert Watson {
212c66b4d8dSRobert Watson 
213c66b4d8dSRobert Watson 	MAC_PERFORM(create_socket, cred, socket, socket->so_label);
214c66b4d8dSRobert Watson }
215c66b4d8dSRobert Watson 
216c66b4d8dSRobert Watson void
217c66b4d8dSRobert Watson mac_create_socket_from_socket(struct socket *oldsocket,
218c66b4d8dSRobert Watson     struct socket *newsocket)
219c66b4d8dSRobert Watson {
220c66b4d8dSRobert Watson 
221310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(oldsocket);
222c66b4d8dSRobert Watson 	MAC_PERFORM(create_socket_from_socket, oldsocket, oldsocket->so_label,
223c66b4d8dSRobert Watson 	    newsocket, newsocket->so_label);
224c66b4d8dSRobert Watson }
225c66b4d8dSRobert Watson 
226c66b4d8dSRobert Watson static void
227c66b4d8dSRobert Watson mac_relabel_socket(struct ucred *cred, struct socket *socket,
228c66b4d8dSRobert Watson     struct label *newlabel)
229c66b4d8dSRobert Watson {
230c66b4d8dSRobert Watson 
231310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
232c66b4d8dSRobert Watson 	MAC_PERFORM(relabel_socket, cred, socket, socket->so_label, newlabel);
233c66b4d8dSRobert Watson }
234c66b4d8dSRobert Watson 
235c66b4d8dSRobert Watson void
236c66b4d8dSRobert Watson mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket)
237c66b4d8dSRobert Watson {
238c66b4d8dSRobert Watson 	struct label *label;
239c66b4d8dSRobert Watson 
240310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
241310e7cebSRobert Watson 
242c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
243c66b4d8dSRobert Watson 
244c66b4d8dSRobert Watson 	MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, label, socket,
245c66b4d8dSRobert Watson 	    socket->so_peerlabel);
246c66b4d8dSRobert Watson }
247c66b4d8dSRobert Watson 
248c66b4d8dSRobert Watson void
249c66b4d8dSRobert Watson mac_set_socket_peer_from_socket(struct socket *oldsocket,
250c66b4d8dSRobert Watson     struct socket *newsocket)
251c66b4d8dSRobert Watson {
252c66b4d8dSRobert Watson 
253310e7cebSRobert Watson 	/*
254310e7cebSRobert Watson 	 * XXXRW: only hold the socket lock on one at a time, as one
255310e7cebSRobert Watson 	 * socket is the original, and one is the new.  However, it's
256310e7cebSRobert Watson 	 * called in both directions, so we can't assert the lock
257310e7cebSRobert Watson 	 * here currently.
258310e7cebSRobert Watson 	 */
259c66b4d8dSRobert Watson 	MAC_PERFORM(set_socket_peer_from_socket, oldsocket,
260c66b4d8dSRobert Watson 	    oldsocket->so_label, newsocket, newsocket->so_peerlabel);
261c66b4d8dSRobert Watson }
262c66b4d8dSRobert Watson 
263c66b4d8dSRobert Watson void
264c66b4d8dSRobert Watson mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf)
265c66b4d8dSRobert Watson {
266c66b4d8dSRobert Watson 	struct label *label;
267c66b4d8dSRobert Watson 
268c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
269c66b4d8dSRobert Watson 
270310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
271c66b4d8dSRobert Watson 	MAC_PERFORM(create_mbuf_from_socket, socket, socket->so_label, mbuf,
272c66b4d8dSRobert Watson 	    label);
273c66b4d8dSRobert Watson }
274c66b4d8dSRobert Watson 
275c66b4d8dSRobert Watson int
276c66b4d8dSRobert Watson mac_check_socket_bind(struct ucred *ucred, struct socket *socket,
277c66b4d8dSRobert Watson     struct sockaddr *sockaddr)
278c66b4d8dSRobert Watson {
279c66b4d8dSRobert Watson 	int error;
280c66b4d8dSRobert Watson 
281310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
282310e7cebSRobert Watson 
283c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
284c66b4d8dSRobert Watson 		return (0);
285c66b4d8dSRobert Watson 
286c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_bind, ucred, socket, socket->so_label,
287c66b4d8dSRobert Watson 	    sockaddr);
288c66b4d8dSRobert Watson 
289c66b4d8dSRobert Watson 	return (error);
290c66b4d8dSRobert Watson }
291c66b4d8dSRobert Watson 
292c66b4d8dSRobert Watson int
293c66b4d8dSRobert Watson mac_check_socket_connect(struct ucred *cred, struct socket *socket,
294c66b4d8dSRobert Watson     struct sockaddr *sockaddr)
295c66b4d8dSRobert Watson {
296c66b4d8dSRobert Watson 	int error;
297c66b4d8dSRobert Watson 
298310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
299310e7cebSRobert Watson 
300c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
301c66b4d8dSRobert Watson 		return (0);
302c66b4d8dSRobert Watson 
303c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_connect, cred, socket, socket->so_label,
304c66b4d8dSRobert Watson 	    sockaddr);
305c66b4d8dSRobert Watson 
306c66b4d8dSRobert Watson 	return (error);
307c66b4d8dSRobert Watson }
308c66b4d8dSRobert Watson 
309c66b4d8dSRobert Watson int
310c66b4d8dSRobert Watson mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf)
311c66b4d8dSRobert Watson {
312c66b4d8dSRobert Watson 	struct label *label;
313c66b4d8dSRobert Watson 	int error;
314c66b4d8dSRobert Watson 
315310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
316310e7cebSRobert Watson 
317c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
318c66b4d8dSRobert Watson 		return (0);
319c66b4d8dSRobert Watson 
320c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
321c66b4d8dSRobert Watson 
322c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_deliver, socket, socket->so_label, mbuf,
323c66b4d8dSRobert Watson 	    label);
324c66b4d8dSRobert Watson 
325c66b4d8dSRobert Watson 	return (error);
326c66b4d8dSRobert Watson }
327c66b4d8dSRobert Watson 
328c66b4d8dSRobert Watson int
329c66b4d8dSRobert Watson mac_check_socket_listen(struct ucred *cred, struct socket *socket)
330c66b4d8dSRobert Watson {
331c66b4d8dSRobert Watson 	int error;
332c66b4d8dSRobert Watson 
333310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
334310e7cebSRobert Watson 
335c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
336c66b4d8dSRobert Watson 		return (0);
337c66b4d8dSRobert Watson 
338c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_listen, cred, socket, socket->so_label);
339c66b4d8dSRobert Watson 	return (error);
340c66b4d8dSRobert Watson }
341c66b4d8dSRobert Watson 
342c66b4d8dSRobert Watson int
343c66b4d8dSRobert Watson mac_check_socket_receive(struct ucred *cred, struct socket *so)
344c66b4d8dSRobert Watson {
345c66b4d8dSRobert Watson 	int error;
346c66b4d8dSRobert Watson 
347310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
348310e7cebSRobert Watson 
349c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
350c66b4d8dSRobert Watson 		return (0);
351c66b4d8dSRobert Watson 
352c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_receive, cred, so, so->so_label);
353c66b4d8dSRobert Watson 
354c66b4d8dSRobert Watson 	return (error);
355c66b4d8dSRobert Watson }
356c66b4d8dSRobert Watson 
357c66b4d8dSRobert Watson static int
358c66b4d8dSRobert Watson mac_check_socket_relabel(struct ucred *cred, struct socket *socket,
359c66b4d8dSRobert Watson     struct label *newlabel)
360c66b4d8dSRobert Watson {
361c66b4d8dSRobert Watson 	int error;
362c66b4d8dSRobert Watson 
363310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
364310e7cebSRobert Watson 
365c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_relabel, cred, socket, socket->so_label,
366c66b4d8dSRobert Watson 	    newlabel);
367c66b4d8dSRobert Watson 
368c66b4d8dSRobert Watson 	return (error);
369c66b4d8dSRobert Watson }
370c66b4d8dSRobert Watson 
371c66b4d8dSRobert Watson int
372c66b4d8dSRobert Watson mac_check_socket_send(struct ucred *cred, struct socket *so)
373c66b4d8dSRobert Watson {
374c66b4d8dSRobert Watson 	int error;
375c66b4d8dSRobert Watson 
376310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
377310e7cebSRobert Watson 
378c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
379c66b4d8dSRobert Watson 		return (0);
380c66b4d8dSRobert Watson 
381c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_send, cred, so, so->so_label);
382c66b4d8dSRobert Watson 
383c66b4d8dSRobert Watson 	return (error);
384c66b4d8dSRobert Watson }
385c66b4d8dSRobert Watson 
386c66b4d8dSRobert Watson int
387c66b4d8dSRobert Watson mac_check_socket_visible(struct ucred *cred, struct socket *socket)
388c66b4d8dSRobert Watson {
389c66b4d8dSRobert Watson 	int error;
390c66b4d8dSRobert Watson 
391310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
392310e7cebSRobert Watson 
393c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
394c66b4d8dSRobert Watson 		return (0);
395c66b4d8dSRobert Watson 
396c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_visible, cred, socket, socket->so_label);
397c66b4d8dSRobert Watson 
398c66b4d8dSRobert Watson 	return (error);
399c66b4d8dSRobert Watson }
400c66b4d8dSRobert Watson 
401c66b4d8dSRobert Watson int
402c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so,
403c66b4d8dSRobert Watson     struct label *label)
404c66b4d8dSRobert Watson {
405c66b4d8dSRobert Watson 	int error;
406c66b4d8dSRobert Watson 
407310e7cebSRobert Watson 	/*
408310e7cebSRobert Watson 	 * We acquire the socket lock when we perform the test and set,
409310e7cebSRobert Watson 	 * but have to release it as the pcb code needs to acquire the
410310e7cebSRobert Watson 	 * pcb lock, which will precede the socket lock in the lock
411310e7cebSRobert Watson 	 * order.  However, this is fine, as any race will simply
412310e7cebSRobert Watson 	 * result in the inpcb being refreshed twice, but still
413310e7cebSRobert Watson 	 * consistently, as the inpcb code will acquire the socket lock
414310e7cebSRobert Watson 	 * before refreshing, holding both locks.
415310e7cebSRobert Watson 	 */
416310e7cebSRobert Watson 	SOCK_LOCK(so);
417c66b4d8dSRobert Watson 	error = mac_check_socket_relabel(cred, so, label);
418310e7cebSRobert Watson 	if (error) {
419310e7cebSRobert Watson 		SOCK_UNLOCK(so);
420c66b4d8dSRobert Watson 		return (error);
421310e7cebSRobert Watson 	}
422c66b4d8dSRobert Watson 
423c66b4d8dSRobert Watson 	mac_relabel_socket(cred, so, label);
424310e7cebSRobert Watson 	SOCK_UNLOCK(so);
425c66b4d8dSRobert Watson 	/*
426c66b4d8dSRobert Watson 	 * If the protocol has expressed interest in socket layer changes,
427c66b4d8dSRobert Watson 	 * such as if it needs to propagate changes to a cached pcb
428c66b4d8dSRobert Watson 	 * label from the socket, notify it of the label change while
429c66b4d8dSRobert Watson 	 * holding the socket lock.
430c66b4d8dSRobert Watson 	 */
431c66b4d8dSRobert Watson 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
432c66b4d8dSRobert Watson 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
433c66b4d8dSRobert Watson 
434c66b4d8dSRobert Watson 	return (0);
435c66b4d8dSRobert Watson }
436c66b4d8dSRobert Watson 
437c66b4d8dSRobert Watson int
438c66b4d8dSRobert Watson mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
439c66b4d8dSRobert Watson {
440c66b4d8dSRobert Watson 	struct label *intlabel;
441c66b4d8dSRobert Watson 	char *buffer;
442c66b4d8dSRobert Watson 	int error;
443c66b4d8dSRobert Watson 
444c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
445c66b4d8dSRobert Watson 	if (error)
446c66b4d8dSRobert Watson 		return (error);
447c66b4d8dSRobert Watson 
448c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
449c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
450c66b4d8dSRobert Watson 	if (error) {
451c66b4d8dSRobert Watson 		free(buffer, M_MACTEMP);
452c66b4d8dSRobert Watson 		return (error);
453c66b4d8dSRobert Watson 	}
454c66b4d8dSRobert Watson 
455c66b4d8dSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
456c66b4d8dSRobert Watson 	error = mac_internalize_socket_label(intlabel, buffer);
457c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
458c66b4d8dSRobert Watson 	if (error)
459c66b4d8dSRobert Watson 		goto out;
460c66b4d8dSRobert Watson 
461c66b4d8dSRobert Watson 	error = mac_socket_label_set(cred, so, intlabel);
462c66b4d8dSRobert Watson out:
463c66b4d8dSRobert Watson 	mac_socket_label_free(intlabel);
464c66b4d8dSRobert Watson 	return (error);
465c66b4d8dSRobert Watson }
466c66b4d8dSRobert Watson 
467c66b4d8dSRobert Watson int
468c66b4d8dSRobert Watson mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
469c66b4d8dSRobert Watson {
470c66b4d8dSRobert Watson 	char *buffer, *elements;
471310e7cebSRobert Watson 	struct label *intlabel;
472c66b4d8dSRobert Watson 	int error;
473c66b4d8dSRobert Watson 
474c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
475c66b4d8dSRobert Watson 	if (error)
476c66b4d8dSRobert Watson 		return (error);
477c66b4d8dSRobert Watson 
478c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
479c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
480c66b4d8dSRobert Watson 	if (error) {
481c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
482c66b4d8dSRobert Watson 		return (error);
483c66b4d8dSRobert Watson 	}
484c66b4d8dSRobert Watson 
485c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
486310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
487310e7cebSRobert Watson 	SOCK_LOCK(so);
488310e7cebSRobert Watson 	mac_copy_socket_label(so->so_label, intlabel);
489310e7cebSRobert Watson 	SOCK_UNLOCK(so);
490310e7cebSRobert Watson 	error = mac_externalize_socket_label(intlabel, elements, buffer,
491310e7cebSRobert Watson 	    mac->m_buflen);
492310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
493c66b4d8dSRobert Watson 	if (error == 0)
494c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
495c66b4d8dSRobert Watson 
496c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
497c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
498c66b4d8dSRobert Watson 
499c66b4d8dSRobert Watson 	return (error);
500c66b4d8dSRobert Watson }
501c66b4d8dSRobert Watson 
502c66b4d8dSRobert Watson int
503c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
504c66b4d8dSRobert Watson     struct mac *mac)
505c66b4d8dSRobert Watson {
506c66b4d8dSRobert Watson 	char *elements, *buffer;
507310e7cebSRobert Watson 	struct label *intlabel;
508c66b4d8dSRobert Watson 	int error;
509c66b4d8dSRobert Watson 
510c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
511c66b4d8dSRobert Watson 	if (error)
512c66b4d8dSRobert Watson 		return (error);
513c66b4d8dSRobert Watson 
514c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
515c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
516c66b4d8dSRobert Watson 	if (error) {
517c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
518c66b4d8dSRobert Watson 		return (error);
519c66b4d8dSRobert Watson 	}
520c66b4d8dSRobert Watson 
521c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
522310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
523310e7cebSRobert Watson 	SOCK_LOCK(so);
524310e7cebSRobert Watson 	mac_copy_socket_label(so->so_peerlabel, intlabel);
525310e7cebSRobert Watson 	SOCK_UNLOCK(so);
526310e7cebSRobert Watson 	error = mac_externalize_socket_peer_label(intlabel, elements, buffer,
527310e7cebSRobert Watson 	    mac->m_buflen);
528310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
529c66b4d8dSRobert Watson 	if (error == 0)
530c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
531c66b4d8dSRobert Watson 
532c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
533c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
534c66b4d8dSRobert Watson 
535c66b4d8dSRobert Watson 	return (error);
536c66b4d8dSRobert Watson }
537