xref: /freebsd/sys/security/mac/mac_socket.c (revision df3c68e479bbda28028c339612d2a174de30298e)
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 
72aed55708SRobert Watson #include <security/mac/mac_framework.h>
73c66b4d8dSRobert Watson #include <security/mac/mac_internal.h>
74c66b4d8dSRobert Watson 
75c66b4d8dSRobert Watson /*
76c66b4d8dSRobert Watson  * mac_enforce_socket is used by the inet code when delivering to an inpcb
77c66b4d8dSRobert Watson  * without hitting the socket layer, and has to be non-static for now.
78c66b4d8dSRobert Watson  */
79c66b4d8dSRobert Watson int	mac_enforce_socket = 1;
80c66b4d8dSRobert Watson SYSCTL_INT(_security_mac, OID_AUTO, enforce_socket, CTLFLAG_RW,
81c66b4d8dSRobert Watson     &mac_enforce_socket, 0, "Enforce MAC policy on socket operations");
82c66b4d8dSRobert Watson TUNABLE_INT("security.mac.enforce_socket", &mac_enforce_socket);
83c66b4d8dSRobert Watson 
84df3c68e4SRobert Watson /*
85df3c68e4SRobert Watson  * Currently, sockets hold two labels: the label of the socket itself, and a
86df3c68e4SRobert Watson  * peer label, which may be used by policies to hold a copy of the label of
87df3c68e4SRobert Watson  * any remote endpoint.
88df3c68e4SRobert Watson  *
89df3c68e4SRobert Watson  * Possibly, this peer label should be maintained at the protocol layer
90df3c68e4SRobert Watson  * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
91df3c68e4SRobert Watson  * the label consistently.  For example, it might be copied live from a
92df3c68e4SRobert Watson  * remote socket for UNIX domain sockets rather than keeping a local copy on
93df3c68e4SRobert Watson  * this endpoint, but be cached and updated based on packets received for
94df3c68e4SRobert Watson  * TCP/IP.
95df3c68e4SRobert Watson  */
96df3c68e4SRobert Watson 
97c66b4d8dSRobert Watson struct label *
98c66b4d8dSRobert Watson mac_socket_label_alloc(int flag)
99c66b4d8dSRobert Watson {
100c66b4d8dSRobert Watson 	struct label *label;
101c66b4d8dSRobert Watson 	int error;
102c66b4d8dSRobert Watson 
103c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
104c66b4d8dSRobert Watson 	if (label == NULL)
105c66b4d8dSRobert Watson 		return (NULL);
106c66b4d8dSRobert Watson 
107c66b4d8dSRobert Watson 	MAC_CHECK(init_socket_label, label, flag);
108c66b4d8dSRobert Watson 	if (error) {
109c66b4d8dSRobert Watson 		MAC_PERFORM(destroy_socket_label, label);
110c66b4d8dSRobert Watson 		mac_labelzone_free(label);
111c66b4d8dSRobert Watson 		return (NULL);
112c66b4d8dSRobert Watson 	}
113c66b4d8dSRobert Watson 	return (label);
114c66b4d8dSRobert Watson }
115c66b4d8dSRobert Watson 
116c66b4d8dSRobert Watson static struct label *
117c66b4d8dSRobert Watson mac_socket_peer_label_alloc(int flag)
118c66b4d8dSRobert Watson {
119c66b4d8dSRobert Watson 	struct label *label;
120c66b4d8dSRobert Watson 	int error;
121c66b4d8dSRobert Watson 
122c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
123c66b4d8dSRobert Watson 	if (label == NULL)
124c66b4d8dSRobert Watson 		return (NULL);
125c66b4d8dSRobert Watson 
126c66b4d8dSRobert Watson 	MAC_CHECK(init_socket_peer_label, label, flag);
127c66b4d8dSRobert Watson 	if (error) {
128c66b4d8dSRobert Watson 		MAC_PERFORM(destroy_socket_peer_label, label);
129c66b4d8dSRobert Watson 		mac_labelzone_free(label);
130c66b4d8dSRobert Watson 		return (NULL);
131c66b4d8dSRobert Watson 	}
132c66b4d8dSRobert Watson 	return (label);
133c66b4d8dSRobert Watson }
134c66b4d8dSRobert Watson 
135c66b4d8dSRobert Watson int
136c66b4d8dSRobert Watson mac_init_socket(struct socket *so, int flag)
137c66b4d8dSRobert Watson {
138c66b4d8dSRobert Watson 
139c66b4d8dSRobert Watson 	so->so_label = mac_socket_label_alloc(flag);
140c66b4d8dSRobert Watson 	if (so->so_label == NULL)
141c66b4d8dSRobert Watson 		return (ENOMEM);
142c66b4d8dSRobert Watson 	so->so_peerlabel = mac_socket_peer_label_alloc(flag);
143c66b4d8dSRobert Watson 	if (so->so_peerlabel == NULL) {
144c66b4d8dSRobert Watson 		mac_socket_label_free(so->so_label);
145c66b4d8dSRobert Watson 		so->so_label = NULL;
146c66b4d8dSRobert Watson 		return (ENOMEM);
147c66b4d8dSRobert Watson 	}
148c66b4d8dSRobert Watson 	return (0);
149c66b4d8dSRobert Watson }
150c66b4d8dSRobert Watson 
151c66b4d8dSRobert Watson void
152c66b4d8dSRobert Watson mac_socket_label_free(struct label *label)
153c66b4d8dSRobert Watson {
154c66b4d8dSRobert Watson 
155c66b4d8dSRobert Watson 	MAC_PERFORM(destroy_socket_label, label);
156c66b4d8dSRobert Watson 	mac_labelzone_free(label);
157c66b4d8dSRobert Watson }
158c66b4d8dSRobert Watson 
159c66b4d8dSRobert Watson static void
160c66b4d8dSRobert Watson mac_socket_peer_label_free(struct label *label)
161c66b4d8dSRobert Watson {
162c66b4d8dSRobert Watson 
163c66b4d8dSRobert Watson 	MAC_PERFORM(destroy_socket_peer_label, label);
164c66b4d8dSRobert Watson 	mac_labelzone_free(label);
165c66b4d8dSRobert Watson }
166c66b4d8dSRobert Watson 
167c66b4d8dSRobert Watson void
168c66b4d8dSRobert Watson mac_destroy_socket(struct socket *socket)
169c66b4d8dSRobert Watson {
170c66b4d8dSRobert Watson 
171c66b4d8dSRobert Watson 	mac_socket_label_free(socket->so_label);
172c66b4d8dSRobert Watson 	socket->so_label = NULL;
173c66b4d8dSRobert Watson 	mac_socket_peer_label_free(socket->so_peerlabel);
174c66b4d8dSRobert Watson 	socket->so_peerlabel = NULL;
175c66b4d8dSRobert Watson }
176c66b4d8dSRobert Watson 
177c66b4d8dSRobert Watson void
178c66b4d8dSRobert Watson mac_copy_socket_label(struct label *src, struct label *dest)
179c66b4d8dSRobert Watson {
180c66b4d8dSRobert Watson 
181c66b4d8dSRobert Watson 	MAC_PERFORM(copy_socket_label, src, dest);
182c66b4d8dSRobert Watson }
183c66b4d8dSRobert Watson 
184c66b4d8dSRobert Watson int
185c66b4d8dSRobert Watson mac_externalize_socket_label(struct label *label, char *elements,
186c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
187c66b4d8dSRobert Watson {
188c66b4d8dSRobert Watson 	int error;
189c66b4d8dSRobert Watson 
190c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
191c66b4d8dSRobert Watson 
192c66b4d8dSRobert Watson 	return (error);
193c66b4d8dSRobert Watson }
194c66b4d8dSRobert Watson 
195c66b4d8dSRobert Watson static int
196c66b4d8dSRobert Watson mac_externalize_socket_peer_label(struct label *label, char *elements,
197c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
198c66b4d8dSRobert Watson {
199c66b4d8dSRobert Watson 	int error;
200c66b4d8dSRobert Watson 
201c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket_peer, label, elements, outbuf, outbuflen);
202c66b4d8dSRobert Watson 
203c66b4d8dSRobert Watson 	return (error);
204c66b4d8dSRobert Watson }
205c66b4d8dSRobert Watson 
206c66b4d8dSRobert Watson int
207c66b4d8dSRobert Watson mac_internalize_socket_label(struct label *label, char *string)
208c66b4d8dSRobert Watson {
209c66b4d8dSRobert Watson 	int error;
210c66b4d8dSRobert Watson 
211c66b4d8dSRobert Watson 	MAC_INTERNALIZE(socket, label, string);
212c66b4d8dSRobert Watson 
213c66b4d8dSRobert Watson 	return (error);
214c66b4d8dSRobert Watson }
215c66b4d8dSRobert Watson 
216c66b4d8dSRobert Watson void
217c66b4d8dSRobert Watson mac_create_socket(struct ucred *cred, struct socket *socket)
218c66b4d8dSRobert Watson {
219c66b4d8dSRobert Watson 
220c66b4d8dSRobert Watson 	MAC_PERFORM(create_socket, cred, socket, socket->so_label);
221c66b4d8dSRobert Watson }
222c66b4d8dSRobert Watson 
223c66b4d8dSRobert Watson void
224c66b4d8dSRobert Watson mac_create_socket_from_socket(struct socket *oldsocket,
225c66b4d8dSRobert Watson     struct socket *newsocket)
226c66b4d8dSRobert Watson {
227c66b4d8dSRobert Watson 
228310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(oldsocket);
229c66b4d8dSRobert Watson 	MAC_PERFORM(create_socket_from_socket, oldsocket, oldsocket->so_label,
230c66b4d8dSRobert Watson 	    newsocket, newsocket->so_label);
231c66b4d8dSRobert Watson }
232c66b4d8dSRobert Watson 
233c66b4d8dSRobert Watson static void
234c66b4d8dSRobert Watson mac_relabel_socket(struct ucred *cred, struct socket *socket,
235c66b4d8dSRobert Watson     struct label *newlabel)
236c66b4d8dSRobert Watson {
237c66b4d8dSRobert Watson 
238310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
239c66b4d8dSRobert Watson 	MAC_PERFORM(relabel_socket, cred, socket, socket->so_label, newlabel);
240c66b4d8dSRobert Watson }
241c66b4d8dSRobert Watson 
242c66b4d8dSRobert Watson void
243c66b4d8dSRobert Watson mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket)
244c66b4d8dSRobert Watson {
245c66b4d8dSRobert Watson 	struct label *label;
246c66b4d8dSRobert Watson 
247310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
248310e7cebSRobert Watson 
249c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
250c66b4d8dSRobert Watson 
251c66b4d8dSRobert Watson 	MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, label, socket,
252c66b4d8dSRobert Watson 	    socket->so_peerlabel);
253c66b4d8dSRobert Watson }
254c66b4d8dSRobert Watson 
255c66b4d8dSRobert Watson void
256c66b4d8dSRobert Watson mac_set_socket_peer_from_socket(struct socket *oldsocket,
257c66b4d8dSRobert Watson     struct socket *newsocket)
258c66b4d8dSRobert Watson {
259c66b4d8dSRobert Watson 
260310e7cebSRobert Watson 	/*
261df3c68e4SRobert Watson 	 * XXXRW: only hold the socket lock on one at a time, as one socket
262df3c68e4SRobert Watson 	 * is the original, and one is the new.  However, it's called in both
263df3c68e4SRobert Watson 	 * directions, so we can't assert the lock here currently.
264310e7cebSRobert Watson 	 */
265c66b4d8dSRobert Watson 	MAC_PERFORM(set_socket_peer_from_socket, oldsocket,
266c66b4d8dSRobert Watson 	    oldsocket->so_label, newsocket, newsocket->so_peerlabel);
267c66b4d8dSRobert Watson }
268c66b4d8dSRobert Watson 
269c66b4d8dSRobert Watson void
270c66b4d8dSRobert Watson mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf)
271c66b4d8dSRobert Watson {
272c66b4d8dSRobert Watson 	struct label *label;
273c66b4d8dSRobert Watson 
274c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
275c66b4d8dSRobert Watson 
276310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
277c66b4d8dSRobert Watson 	MAC_PERFORM(create_mbuf_from_socket, socket, socket->so_label, mbuf,
278c66b4d8dSRobert Watson 	    label);
279c66b4d8dSRobert Watson }
280c66b4d8dSRobert Watson 
281c66b4d8dSRobert Watson int
2827f53207bSRobert Watson mac_check_socket_accept(struct ucred *cred, struct socket *socket)
2837f53207bSRobert Watson {
2847f53207bSRobert Watson 	int error;
2857f53207bSRobert Watson 
2867f53207bSRobert Watson 	SOCK_LOCK_ASSERT(socket);
2877f53207bSRobert Watson 
2887f53207bSRobert Watson 	if (!mac_enforce_socket)
2897f53207bSRobert Watson 		return (0);
2907f53207bSRobert Watson 
2917f53207bSRobert Watson 	MAC_CHECK(check_socket_accept, cred, socket, socket->so_label);
2927f53207bSRobert Watson 
2937f53207bSRobert Watson 	return (error);
2947f53207bSRobert Watson }
2957f53207bSRobert Watson 
2967f53207bSRobert Watson int
297c66b4d8dSRobert Watson mac_check_socket_bind(struct ucred *ucred, struct socket *socket,
298c66b4d8dSRobert Watson     struct sockaddr *sockaddr)
299c66b4d8dSRobert Watson {
300c66b4d8dSRobert Watson 	int error;
301c66b4d8dSRobert Watson 
302310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
303310e7cebSRobert Watson 
304c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
305c66b4d8dSRobert Watson 		return (0);
306c66b4d8dSRobert Watson 
307c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_bind, ucred, socket, socket->so_label,
308c66b4d8dSRobert Watson 	    sockaddr);
309c66b4d8dSRobert Watson 
310c66b4d8dSRobert Watson 	return (error);
311c66b4d8dSRobert Watson }
312c66b4d8dSRobert Watson 
313c66b4d8dSRobert Watson int
314c66b4d8dSRobert Watson mac_check_socket_connect(struct ucred *cred, struct socket *socket,
315c66b4d8dSRobert Watson     struct sockaddr *sockaddr)
316c66b4d8dSRobert Watson {
317c66b4d8dSRobert Watson 	int error;
318c66b4d8dSRobert Watson 
319310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
320310e7cebSRobert Watson 
321c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
322c66b4d8dSRobert Watson 		return (0);
323c66b4d8dSRobert Watson 
324c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_connect, cred, socket, socket->so_label,
325c66b4d8dSRobert Watson 	    sockaddr);
326c66b4d8dSRobert Watson 
327c66b4d8dSRobert Watson 	return (error);
328c66b4d8dSRobert Watson }
329c66b4d8dSRobert Watson 
330c66b4d8dSRobert Watson int
3316758f88eSRobert Watson mac_check_socket_create(struct ucred *cred, int domain, int type,
3326758f88eSRobert Watson     int protocol)
3336758f88eSRobert Watson {
3346758f88eSRobert Watson 	int error;
3356758f88eSRobert Watson 
3366758f88eSRobert Watson 	if (!mac_enforce_socket)
3376758f88eSRobert Watson 		return (0);
3386758f88eSRobert Watson 
3396758f88eSRobert Watson 	MAC_CHECK(check_socket_create, cred, domain, type, protocol);
3406758f88eSRobert Watson 
3416758f88eSRobert Watson 	return (error);
3426758f88eSRobert Watson }
3436758f88eSRobert Watson 
3446758f88eSRobert Watson int
345c66b4d8dSRobert Watson mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf)
346c66b4d8dSRobert Watson {
347c66b4d8dSRobert Watson 	struct label *label;
348c66b4d8dSRobert Watson 	int error;
349c66b4d8dSRobert Watson 
350310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
351310e7cebSRobert Watson 
352c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
353c66b4d8dSRobert Watson 		return (0);
354c66b4d8dSRobert Watson 
355c66b4d8dSRobert Watson 	label = mac_mbuf_to_label(mbuf);
356c66b4d8dSRobert Watson 
357c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_deliver, socket, socket->so_label, mbuf,
358c66b4d8dSRobert Watson 	    label);
359c66b4d8dSRobert Watson 
360c66b4d8dSRobert Watson 	return (error);
361c66b4d8dSRobert Watson }
362c66b4d8dSRobert Watson 
363c66b4d8dSRobert Watson int
364c66b4d8dSRobert Watson mac_check_socket_listen(struct ucred *cred, struct socket *socket)
365c66b4d8dSRobert Watson {
366c66b4d8dSRobert Watson 	int error;
367c66b4d8dSRobert Watson 
368310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
369310e7cebSRobert Watson 
370c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
371c66b4d8dSRobert Watson 		return (0);
372c66b4d8dSRobert Watson 
373c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_listen, cred, socket, socket->so_label);
374c66b4d8dSRobert Watson 	return (error);
375c66b4d8dSRobert Watson }
376c66b4d8dSRobert Watson 
377c66b4d8dSRobert Watson int
3787f53207bSRobert Watson mac_check_socket_poll(struct ucred *cred, struct socket *so)
3797f53207bSRobert Watson {
3807f53207bSRobert Watson 	int error;
3817f53207bSRobert Watson 
3827f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
3837f53207bSRobert Watson 
3847f53207bSRobert Watson 	if (!mac_enforce_socket)
3857f53207bSRobert Watson 		return (0);
3867f53207bSRobert Watson 
3877f53207bSRobert Watson 	MAC_CHECK(check_socket_poll, cred, so, so->so_label);
3887f53207bSRobert Watson 	return (error);
3897f53207bSRobert Watson }
3907f53207bSRobert Watson 
3917f53207bSRobert Watson int
392c66b4d8dSRobert Watson mac_check_socket_receive(struct ucred *cred, struct socket *so)
393c66b4d8dSRobert Watson {
394c66b4d8dSRobert Watson 	int error;
395c66b4d8dSRobert Watson 
396310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
397310e7cebSRobert Watson 
398c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
399c66b4d8dSRobert Watson 		return (0);
400c66b4d8dSRobert Watson 
401c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_receive, cred, so, so->so_label);
402c66b4d8dSRobert Watson 
403c66b4d8dSRobert Watson 	return (error);
404c66b4d8dSRobert Watson }
405c66b4d8dSRobert Watson 
406c66b4d8dSRobert Watson static int
407c66b4d8dSRobert Watson mac_check_socket_relabel(struct ucred *cred, struct socket *socket,
408c66b4d8dSRobert Watson     struct label *newlabel)
409c66b4d8dSRobert Watson {
410c66b4d8dSRobert Watson 	int error;
411c66b4d8dSRobert Watson 
412310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
413310e7cebSRobert Watson 
414c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_relabel, cred, socket, socket->so_label,
415c66b4d8dSRobert Watson 	    newlabel);
416c66b4d8dSRobert Watson 
417c66b4d8dSRobert Watson 	return (error);
418c66b4d8dSRobert Watson }
419c66b4d8dSRobert Watson 
420c66b4d8dSRobert Watson int
421c66b4d8dSRobert Watson mac_check_socket_send(struct ucred *cred, struct socket *so)
422c66b4d8dSRobert Watson {
423c66b4d8dSRobert Watson 	int error;
424c66b4d8dSRobert Watson 
425310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
426310e7cebSRobert Watson 
427c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
428c66b4d8dSRobert Watson 		return (0);
429c66b4d8dSRobert Watson 
430c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_send, cred, so, so->so_label);
431c66b4d8dSRobert Watson 
432c66b4d8dSRobert Watson 	return (error);
433c66b4d8dSRobert Watson }
434c66b4d8dSRobert Watson 
435c66b4d8dSRobert Watson int
4367f53207bSRobert Watson mac_check_socket_stat(struct ucred *cred, struct socket *so)
4377f53207bSRobert Watson {
4387f53207bSRobert Watson 	int error;
4397f53207bSRobert Watson 
4407f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
4417f53207bSRobert Watson 
4427f53207bSRobert Watson 	if (!mac_enforce_socket)
4437f53207bSRobert Watson 		return (0);
4447f53207bSRobert Watson 
4457f53207bSRobert Watson 	MAC_CHECK(check_socket_stat, cred, so, so->so_label);
4467f53207bSRobert Watson 
4477f53207bSRobert Watson 	return (error);
4487f53207bSRobert Watson }
4497f53207bSRobert Watson 
4507f53207bSRobert Watson int
451c66b4d8dSRobert Watson mac_check_socket_visible(struct ucred *cred, struct socket *socket)
452c66b4d8dSRobert Watson {
453c66b4d8dSRobert Watson 	int error;
454c66b4d8dSRobert Watson 
455310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(socket);
456310e7cebSRobert Watson 
457c66b4d8dSRobert Watson 	if (!mac_enforce_socket)
458c66b4d8dSRobert Watson 		return (0);
459c66b4d8dSRobert Watson 
460c66b4d8dSRobert Watson 	MAC_CHECK(check_socket_visible, cred, socket, socket->so_label);
461c66b4d8dSRobert Watson 
462c66b4d8dSRobert Watson 	return (error);
463c66b4d8dSRobert Watson }
464c66b4d8dSRobert Watson 
465c66b4d8dSRobert Watson int
466c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so,
467c66b4d8dSRobert Watson     struct label *label)
468c66b4d8dSRobert Watson {
469c66b4d8dSRobert Watson 	int error;
470c66b4d8dSRobert Watson 
471310e7cebSRobert Watson 	/*
472df3c68e4SRobert Watson 	 * We acquire the socket lock when we perform the test and set, but
473df3c68e4SRobert Watson 	 * have to release it as the pcb code needs to acquire the pcb lock,
474df3c68e4SRobert Watson 	 * which will precede the socket lock in the lock order.  However,
475df3c68e4SRobert Watson 	 * this is fine, as any race will simply result in the inpcb being
476df3c68e4SRobert Watson 	 * refreshed twice, but still consistently, as the inpcb code will
477df3c68e4SRobert Watson 	 * acquire the socket lock before refreshing, holding both locks.
478310e7cebSRobert Watson 	 */
479310e7cebSRobert Watson 	SOCK_LOCK(so);
480c66b4d8dSRobert Watson 	error = mac_check_socket_relabel(cred, so, label);
481310e7cebSRobert Watson 	if (error) {
482310e7cebSRobert Watson 		SOCK_UNLOCK(so);
483c66b4d8dSRobert Watson 		return (error);
484310e7cebSRobert Watson 	}
485c66b4d8dSRobert Watson 
486c66b4d8dSRobert Watson 	mac_relabel_socket(cred, so, label);
487310e7cebSRobert Watson 	SOCK_UNLOCK(so);
488df3c68e4SRobert Watson 
489c66b4d8dSRobert Watson 	/*
490c66b4d8dSRobert Watson 	 * If the protocol has expressed interest in socket layer changes,
491df3c68e4SRobert Watson 	 * such as if it needs to propagate changes to a cached pcb label
492df3c68e4SRobert Watson 	 * from the socket, notify it of the label change while holding the
493df3c68e4SRobert Watson 	 * socket lock.
494c66b4d8dSRobert Watson 	 */
495c66b4d8dSRobert Watson 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
496c66b4d8dSRobert Watson 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
497c66b4d8dSRobert Watson 
498c66b4d8dSRobert Watson 	return (0);
499c66b4d8dSRobert Watson }
500c66b4d8dSRobert Watson 
501c66b4d8dSRobert Watson int
502c66b4d8dSRobert Watson mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
503c66b4d8dSRobert Watson {
504c66b4d8dSRobert Watson 	struct label *intlabel;
505c66b4d8dSRobert Watson 	char *buffer;
506c66b4d8dSRobert Watson 	int error;
507c66b4d8dSRobert Watson 
508c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
509c66b4d8dSRobert Watson 	if (error)
510c66b4d8dSRobert Watson 		return (error);
511c66b4d8dSRobert Watson 
512c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
513c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
514c66b4d8dSRobert Watson 	if (error) {
515c66b4d8dSRobert Watson 		free(buffer, M_MACTEMP);
516c66b4d8dSRobert Watson 		return (error);
517c66b4d8dSRobert Watson 	}
518c66b4d8dSRobert Watson 
519c66b4d8dSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
520c66b4d8dSRobert Watson 	error = mac_internalize_socket_label(intlabel, buffer);
521c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
522c66b4d8dSRobert Watson 	if (error)
523c66b4d8dSRobert Watson 		goto out;
524c66b4d8dSRobert Watson 
525c66b4d8dSRobert Watson 	error = mac_socket_label_set(cred, so, intlabel);
526c66b4d8dSRobert Watson out:
527c66b4d8dSRobert Watson 	mac_socket_label_free(intlabel);
528c66b4d8dSRobert Watson 	return (error);
529c66b4d8dSRobert Watson }
530c66b4d8dSRobert Watson 
531c66b4d8dSRobert Watson int
532c66b4d8dSRobert Watson mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
533c66b4d8dSRobert Watson {
534c66b4d8dSRobert Watson 	char *buffer, *elements;
535310e7cebSRobert Watson 	struct label *intlabel;
536c66b4d8dSRobert Watson 	int error;
537c66b4d8dSRobert Watson 
538c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
539c66b4d8dSRobert Watson 	if (error)
540c66b4d8dSRobert Watson 		return (error);
541c66b4d8dSRobert Watson 
542c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
543c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
544c66b4d8dSRobert Watson 	if (error) {
545c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
546c66b4d8dSRobert Watson 		return (error);
547c66b4d8dSRobert Watson 	}
548c66b4d8dSRobert Watson 
549c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
550310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
551310e7cebSRobert Watson 	SOCK_LOCK(so);
552310e7cebSRobert Watson 	mac_copy_socket_label(so->so_label, intlabel);
553310e7cebSRobert Watson 	SOCK_UNLOCK(so);
554310e7cebSRobert Watson 	error = mac_externalize_socket_label(intlabel, elements, buffer,
555310e7cebSRobert Watson 	    mac->m_buflen);
556310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
557c66b4d8dSRobert Watson 	if (error == 0)
558c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
559c66b4d8dSRobert Watson 
560c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
561c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
562c66b4d8dSRobert Watson 
563c66b4d8dSRobert Watson 	return (error);
564c66b4d8dSRobert Watson }
565c66b4d8dSRobert Watson 
566c66b4d8dSRobert Watson int
567c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
568c66b4d8dSRobert Watson     struct mac *mac)
569c66b4d8dSRobert Watson {
570c66b4d8dSRobert Watson 	char *elements, *buffer;
571310e7cebSRobert Watson 	struct label *intlabel;
572c66b4d8dSRobert Watson 	int error;
573c66b4d8dSRobert Watson 
574c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
575c66b4d8dSRobert Watson 	if (error)
576c66b4d8dSRobert Watson 		return (error);
577c66b4d8dSRobert Watson 
578c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
579c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
580c66b4d8dSRobert Watson 	if (error) {
581c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
582c66b4d8dSRobert Watson 		return (error);
583c66b4d8dSRobert Watson 	}
584c66b4d8dSRobert Watson 
585c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
586310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
587310e7cebSRobert Watson 	SOCK_LOCK(so);
588310e7cebSRobert Watson 	mac_copy_socket_label(so->so_peerlabel, intlabel);
589310e7cebSRobert Watson 	SOCK_UNLOCK(so);
590310e7cebSRobert Watson 	error = mac_externalize_socket_peer_label(intlabel, elements, buffer,
591310e7cebSRobert Watson 	    mac->m_buflen);
592310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
593c66b4d8dSRobert Watson 	if (error == 0)
594c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
595c66b4d8dSRobert Watson 
596c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
597c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
598c66b4d8dSRobert Watson 
599c66b4d8dSRobert Watson 	return (error);
600c66b4d8dSRobert Watson }
601