xref: /freebsd/sys/security/mac/mac_socket.c (revision 30d239bc4c510432e65a84fa1c14ed67a3ab1c92)
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.
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 <net/bpfdesc.h>
63c66b4d8dSRobert Watson #include <net/if.h>
64c66b4d8dSRobert Watson #include <net/if_var.h>
65c66b4d8dSRobert Watson 
66c66b4d8dSRobert Watson #include <netinet/in.h>
67c66b4d8dSRobert Watson #include <netinet/in_pcb.h>
68c66b4d8dSRobert Watson #include <netinet/ip_var.h>
69c66b4d8dSRobert Watson 
70aed55708SRobert Watson #include <security/mac/mac_framework.h>
71c66b4d8dSRobert Watson #include <security/mac/mac_internal.h>
720efd6615SRobert Watson #include <security/mac/mac_policy.h>
73c66b4d8dSRobert Watson 
74c66b4d8dSRobert Watson /*
75df3c68e4SRobert Watson  * Currently, sockets hold two labels: the label of the socket itself, and a
76df3c68e4SRobert Watson  * peer label, which may be used by policies to hold a copy of the label of
77df3c68e4SRobert Watson  * any remote endpoint.
78df3c68e4SRobert Watson  *
79df3c68e4SRobert Watson  * Possibly, this peer label should be maintained at the protocol layer
80df3c68e4SRobert Watson  * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
81df3c68e4SRobert Watson  * the label consistently.  For example, it might be copied live from a
82df3c68e4SRobert Watson  * remote socket for UNIX domain sockets rather than keeping a local copy on
83df3c68e4SRobert Watson  * this endpoint, but be cached and updated based on packets received for
84df3c68e4SRobert Watson  * TCP/IP.
85df3c68e4SRobert Watson  */
86df3c68e4SRobert Watson 
87c66b4d8dSRobert Watson struct label *
88c66b4d8dSRobert Watson mac_socket_label_alloc(int flag)
89c66b4d8dSRobert Watson {
90c66b4d8dSRobert Watson 	struct label *label;
91c66b4d8dSRobert Watson 	int error;
92c66b4d8dSRobert Watson 
93c66b4d8dSRobert Watson 	label = mac_labelzone_alloc(flag);
94c66b4d8dSRobert Watson 	if (label == NULL)
95c66b4d8dSRobert Watson 		return (NULL);
96c66b4d8dSRobert Watson 
9730d239bcSRobert Watson 	MAC_CHECK(socket_init_label, label, flag);
98c66b4d8dSRobert Watson 	if (error) {
9930d239bcSRobert Watson 		MAC_PERFORM(socket_destroy_label, label);
100c66b4d8dSRobert Watson 		mac_labelzone_free(label);
101c66b4d8dSRobert Watson 		return (NULL);
102c66b4d8dSRobert Watson 	}
103c66b4d8dSRobert Watson 	return (label);
104c66b4d8dSRobert Watson }
105c66b4d8dSRobert Watson 
106c66b4d8dSRobert Watson static struct label *
10730d239bcSRobert Watson mac_socketpeer_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 
11630d239bcSRobert Watson 	MAC_CHECK(socketpeer_init_label, label, flag);
117c66b4d8dSRobert Watson 	if (error) {
11830d239bcSRobert Watson 		MAC_PERFORM(socketpeer_destroy_label, label);
119c66b4d8dSRobert Watson 		mac_labelzone_free(label);
120c66b4d8dSRobert Watson 		return (NULL);
121c66b4d8dSRobert Watson 	}
122c66b4d8dSRobert Watson 	return (label);
123c66b4d8dSRobert Watson }
124c66b4d8dSRobert Watson 
125c66b4d8dSRobert Watson int
12630d239bcSRobert Watson mac_socket_init(struct socket *so, int flag)
127c66b4d8dSRobert Watson {
128c66b4d8dSRobert Watson 
129c66b4d8dSRobert Watson 	so->so_label = mac_socket_label_alloc(flag);
130c66b4d8dSRobert Watson 	if (so->so_label == NULL)
131c66b4d8dSRobert Watson 		return (ENOMEM);
13230d239bcSRobert Watson 	so->so_peerlabel = mac_socketpeer_label_alloc(flag);
133c66b4d8dSRobert Watson 	if (so->so_peerlabel == NULL) {
134c66b4d8dSRobert Watson 		mac_socket_label_free(so->so_label);
135c66b4d8dSRobert Watson 		so->so_label = NULL;
136c66b4d8dSRobert Watson 		return (ENOMEM);
137c66b4d8dSRobert Watson 	}
138c66b4d8dSRobert Watson 	return (0);
139c66b4d8dSRobert Watson }
140c66b4d8dSRobert Watson 
141c66b4d8dSRobert Watson void
142c66b4d8dSRobert Watson mac_socket_label_free(struct label *label)
143c66b4d8dSRobert Watson {
144c66b4d8dSRobert Watson 
14530d239bcSRobert Watson 	MAC_PERFORM(socket_destroy_label, label);
146c66b4d8dSRobert Watson 	mac_labelzone_free(label);
147c66b4d8dSRobert Watson }
148c66b4d8dSRobert Watson 
149c66b4d8dSRobert Watson static void
15030d239bcSRobert Watson mac_socketpeer_label_free(struct label *label)
151c66b4d8dSRobert Watson {
152c66b4d8dSRobert Watson 
15330d239bcSRobert Watson 	MAC_PERFORM(socketpeer_destroy_label, label);
154c66b4d8dSRobert Watson 	mac_labelzone_free(label);
155c66b4d8dSRobert Watson }
156c66b4d8dSRobert Watson 
157c66b4d8dSRobert Watson void
15830d239bcSRobert Watson mac_socket_destroy(struct socket *so)
159c66b4d8dSRobert Watson {
160c66b4d8dSRobert Watson 
16126ae2b86SRobert Watson 	mac_socket_label_free(so->so_label);
16226ae2b86SRobert Watson 	so->so_label = NULL;
16330d239bcSRobert Watson 	mac_socketpeer_label_free(so->so_peerlabel);
16426ae2b86SRobert Watson 	so->so_peerlabel = NULL;
165c66b4d8dSRobert Watson }
166c66b4d8dSRobert Watson 
167c66b4d8dSRobert Watson void
16830d239bcSRobert Watson mac_socket_copy_label(struct label *src, struct label *dest)
169c66b4d8dSRobert Watson {
170c66b4d8dSRobert Watson 
17130d239bcSRobert Watson 	MAC_PERFORM(socket_copy_label, src, dest);
172c66b4d8dSRobert Watson }
173c66b4d8dSRobert Watson 
174c66b4d8dSRobert Watson int
17530d239bcSRobert Watson mac_socket_externalize_label(struct label *label, char *elements,
176c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
177c66b4d8dSRobert Watson {
178c66b4d8dSRobert Watson 	int error;
179c66b4d8dSRobert Watson 
180c66b4d8dSRobert Watson 	MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
181c66b4d8dSRobert Watson 
182c66b4d8dSRobert Watson 	return (error);
183c66b4d8dSRobert Watson }
184c66b4d8dSRobert Watson 
185c66b4d8dSRobert Watson static int
18630d239bcSRobert Watson mac_socketpeer_externalize_label(struct label *label, char *elements,
187c66b4d8dSRobert Watson     char *outbuf, size_t outbuflen)
188c66b4d8dSRobert Watson {
189c66b4d8dSRobert Watson 	int error;
190c66b4d8dSRobert Watson 
19130d239bcSRobert Watson 	MAC_EXTERNALIZE(socketpeer, label, elements, outbuf, outbuflen);
192c66b4d8dSRobert Watson 
193c66b4d8dSRobert Watson 	return (error);
194c66b4d8dSRobert Watson }
195c66b4d8dSRobert Watson 
196c66b4d8dSRobert Watson int
19730d239bcSRobert Watson mac_socket_internalize_label(struct label *label, char *string)
198c66b4d8dSRobert Watson {
199c66b4d8dSRobert Watson 	int error;
200c66b4d8dSRobert Watson 
201c66b4d8dSRobert Watson 	MAC_INTERNALIZE(socket, label, string);
202c66b4d8dSRobert Watson 
203c66b4d8dSRobert Watson 	return (error);
204c66b4d8dSRobert Watson }
205c66b4d8dSRobert Watson 
206c66b4d8dSRobert Watson void
20730d239bcSRobert Watson mac_socket_create(struct ucred *cred, struct socket *so)
208c66b4d8dSRobert Watson {
209c66b4d8dSRobert Watson 
21030d239bcSRobert Watson 	MAC_PERFORM(socket_create, cred, so, so->so_label);
211c66b4d8dSRobert Watson }
212c66b4d8dSRobert Watson 
213c66b4d8dSRobert Watson void
21430d239bcSRobert Watson mac_socket_newconn(struct socket *oldso, struct socket *newso)
215c66b4d8dSRobert Watson {
216c66b4d8dSRobert Watson 
21726ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(oldso);
21826ae2b86SRobert Watson 
21930d239bcSRobert Watson 	MAC_PERFORM(socket_newconn, oldso, oldso->so_label, newso,
22026ae2b86SRobert Watson 	    newso->so_label);
221c66b4d8dSRobert Watson }
222c66b4d8dSRobert Watson 
223c66b4d8dSRobert Watson static void
22430d239bcSRobert Watson mac_socket_relabel(struct ucred *cred, struct socket *so,
225c66b4d8dSRobert Watson     struct label *newlabel)
226c66b4d8dSRobert Watson {
227c66b4d8dSRobert Watson 
22826ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
22926ae2b86SRobert Watson 
23030d239bcSRobert Watson 	MAC_PERFORM(socket_relabel, cred, so, so->so_label, newlabel);
231c66b4d8dSRobert Watson }
232c66b4d8dSRobert Watson 
233c66b4d8dSRobert Watson void
23430d239bcSRobert Watson mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
235c66b4d8dSRobert Watson {
236c66b4d8dSRobert Watson 	struct label *label;
237c66b4d8dSRobert Watson 
23826ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
239310e7cebSRobert Watson 
24026ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
241c66b4d8dSRobert Watson 
24230d239bcSRobert Watson 	MAC_PERFORM(socketpeer_set_from_mbuf, m, label, so,
24326ae2b86SRobert Watson 	    so->so_peerlabel);
244c66b4d8dSRobert Watson }
245c66b4d8dSRobert Watson 
246c66b4d8dSRobert Watson void
24730d239bcSRobert Watson mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
248c66b4d8dSRobert Watson {
249c66b4d8dSRobert Watson 
250310e7cebSRobert Watson 	/*
251df3c68e4SRobert Watson 	 * XXXRW: only hold the socket lock on one at a time, as one socket
252df3c68e4SRobert Watson 	 * is the original, and one is the new.  However, it's called in both
253df3c68e4SRobert Watson 	 * directions, so we can't assert the lock here currently.
254310e7cebSRobert Watson 	 */
25530d239bcSRobert Watson 	MAC_PERFORM(socketpeer_set_from_socket, oldso, oldso->so_label,
25626ae2b86SRobert Watson 	    newso, newso->so_peerlabel);
257c66b4d8dSRobert Watson }
258c66b4d8dSRobert Watson 
259c66b4d8dSRobert Watson void
26030d239bcSRobert Watson mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
261c66b4d8dSRobert Watson {
262c66b4d8dSRobert Watson 	struct label *label;
263c66b4d8dSRobert Watson 
26426ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
265c66b4d8dSRobert Watson 
26626ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
26726ae2b86SRobert Watson 
26830d239bcSRobert Watson 	MAC_PERFORM(socket_create_mbuf, so, so->so_label, m, label);
269c66b4d8dSRobert Watson }
270c66b4d8dSRobert Watson 
271c66b4d8dSRobert Watson int
27230d239bcSRobert Watson mac_socket_check_accept(struct ucred *cred, struct socket *so)
2737f53207bSRobert Watson {
2747f53207bSRobert Watson 	int error;
2757f53207bSRobert Watson 
27626ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
2777f53207bSRobert Watson 
27830d239bcSRobert Watson 	MAC_CHECK(socket_check_accept, cred, so, so->so_label);
2797f53207bSRobert Watson 
2807f53207bSRobert Watson 	return (error);
2817f53207bSRobert Watson }
2827f53207bSRobert Watson 
2837f53207bSRobert Watson int
28430d239bcSRobert Watson mac_socket_check_bind(struct ucred *ucred, struct socket *so,
28526ae2b86SRobert Watson     struct sockaddr *sa)
286c66b4d8dSRobert Watson {
287c66b4d8dSRobert Watson 	int error;
288c66b4d8dSRobert Watson 
28926ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
290310e7cebSRobert Watson 
29130d239bcSRobert Watson 	MAC_CHECK(socket_check_bind, ucred, so, so->so_label, sa);
292c66b4d8dSRobert Watson 
293c66b4d8dSRobert Watson 	return (error);
294c66b4d8dSRobert Watson }
295c66b4d8dSRobert Watson 
296c66b4d8dSRobert Watson int
29730d239bcSRobert Watson mac_socket_check_connect(struct ucred *cred, struct socket *so,
29826ae2b86SRobert Watson     struct sockaddr *sa)
299c66b4d8dSRobert Watson {
300c66b4d8dSRobert Watson 	int error;
301c66b4d8dSRobert Watson 
30226ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
303310e7cebSRobert Watson 
30430d239bcSRobert Watson 	MAC_CHECK(socket_check_connect, cred, so, so->so_label, sa);
305c66b4d8dSRobert Watson 
306c66b4d8dSRobert Watson 	return (error);
307c66b4d8dSRobert Watson }
308c66b4d8dSRobert Watson 
309c66b4d8dSRobert Watson int
31030d239bcSRobert Watson mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
3116758f88eSRobert Watson {
3126758f88eSRobert Watson 	int error;
3136758f88eSRobert Watson 
31430d239bcSRobert Watson 	MAC_CHECK(socket_check_create, cred, domain, type, proto);
3156758f88eSRobert Watson 
3166758f88eSRobert Watson 	return (error);
3176758f88eSRobert Watson }
3186758f88eSRobert Watson 
3196758f88eSRobert Watson int
32030d239bcSRobert Watson mac_socket_check_deliver(struct socket *so, struct mbuf *m)
321c66b4d8dSRobert Watson {
322c66b4d8dSRobert Watson 	struct label *label;
323c66b4d8dSRobert Watson 	int error;
324c66b4d8dSRobert Watson 
32526ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
326310e7cebSRobert Watson 
32726ae2b86SRobert Watson 	label = mac_mbuf_to_label(m);
328c66b4d8dSRobert Watson 
32930d239bcSRobert Watson 	MAC_CHECK(socket_check_deliver, so, so->so_label, m, label);
330c66b4d8dSRobert Watson 
331c66b4d8dSRobert Watson 	return (error);
332c66b4d8dSRobert Watson }
333c66b4d8dSRobert Watson 
334c66b4d8dSRobert Watson int
33530d239bcSRobert Watson mac_socket_check_listen(struct ucred *cred, struct socket *so)
336c66b4d8dSRobert Watson {
337c66b4d8dSRobert Watson 	int error;
338c66b4d8dSRobert Watson 
33926ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
340310e7cebSRobert Watson 
34130d239bcSRobert Watson 	MAC_CHECK(socket_check_listen, cred, so, so->so_label);
34226ae2b86SRobert Watson 
343c66b4d8dSRobert Watson 	return (error);
344c66b4d8dSRobert Watson }
345c66b4d8dSRobert Watson 
346c66b4d8dSRobert Watson int
34730d239bcSRobert Watson mac_socket_check_poll(struct ucred *cred, struct socket *so)
3487f53207bSRobert Watson {
3497f53207bSRobert Watson 	int error;
3507f53207bSRobert Watson 
3517f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
3527f53207bSRobert Watson 
35330d239bcSRobert Watson 	MAC_CHECK(socket_check_poll, cred, so, so->so_label);
35426ae2b86SRobert Watson 
3557f53207bSRobert Watson 	return (error);
3567f53207bSRobert Watson }
3577f53207bSRobert Watson 
3587f53207bSRobert Watson int
35930d239bcSRobert Watson mac_socket_check_receive(struct ucred *cred, struct socket *so)
360c66b4d8dSRobert Watson {
361c66b4d8dSRobert Watson 	int error;
362c66b4d8dSRobert Watson 
363310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
364310e7cebSRobert Watson 
36530d239bcSRobert Watson 	MAC_CHECK(socket_check_receive, cred, so, so->so_label);
366c66b4d8dSRobert Watson 
367c66b4d8dSRobert Watson 	return (error);
368c66b4d8dSRobert Watson }
369c66b4d8dSRobert Watson 
370c66b4d8dSRobert Watson static int
37130d239bcSRobert Watson mac_socket_check_relabel(struct ucred *cred, struct socket *so,
372c66b4d8dSRobert Watson     struct label *newlabel)
373c66b4d8dSRobert Watson {
374c66b4d8dSRobert Watson 	int error;
375c66b4d8dSRobert Watson 
37626ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
377310e7cebSRobert Watson 
37830d239bcSRobert Watson 	MAC_CHECK(socket_check_relabel, cred, so, so->so_label, newlabel);
379c66b4d8dSRobert Watson 
380c66b4d8dSRobert Watson 	return (error);
381c66b4d8dSRobert Watson }
382c66b4d8dSRobert Watson 
383c66b4d8dSRobert Watson int
38430d239bcSRobert Watson mac_socket_check_send(struct ucred *cred, struct socket *so)
385c66b4d8dSRobert Watson {
386c66b4d8dSRobert Watson 	int error;
387c66b4d8dSRobert Watson 
388310e7cebSRobert Watson 	SOCK_LOCK_ASSERT(so);
389310e7cebSRobert Watson 
39030d239bcSRobert Watson 	MAC_CHECK(socket_check_send, cred, so, so->so_label);
391c66b4d8dSRobert Watson 
392c66b4d8dSRobert Watson 	return (error);
393c66b4d8dSRobert Watson }
394c66b4d8dSRobert Watson 
395c66b4d8dSRobert Watson int
39630d239bcSRobert Watson mac_socket_check_stat(struct ucred *cred, struct socket *so)
3977f53207bSRobert Watson {
3987f53207bSRobert Watson 	int error;
3997f53207bSRobert Watson 
4007f53207bSRobert Watson 	SOCK_LOCK_ASSERT(so);
4017f53207bSRobert Watson 
40230d239bcSRobert Watson 	MAC_CHECK(socket_check_stat, cred, so, so->so_label);
4037f53207bSRobert Watson 
4047f53207bSRobert Watson 	return (error);
4057f53207bSRobert Watson }
4067f53207bSRobert Watson 
4077f53207bSRobert Watson int
40830d239bcSRobert Watson mac_socket_check_visible(struct ucred *cred, struct socket *so)
409c66b4d8dSRobert Watson {
410c66b4d8dSRobert Watson 	int error;
411c66b4d8dSRobert Watson 
41226ae2b86SRobert Watson 	SOCK_LOCK_ASSERT(so);
413310e7cebSRobert Watson 
41430d239bcSRobert Watson 	MAC_CHECK(socket_check_visible, cred, so, so->so_label);
415c66b4d8dSRobert Watson 
416c66b4d8dSRobert Watson 	return (error);
417c66b4d8dSRobert Watson }
418c66b4d8dSRobert Watson 
419c66b4d8dSRobert Watson int
420c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so,
421c66b4d8dSRobert Watson     struct label *label)
422c66b4d8dSRobert Watson {
423c66b4d8dSRobert Watson 	int error;
424c66b4d8dSRobert Watson 
425310e7cebSRobert Watson 	/*
426df3c68e4SRobert Watson 	 * We acquire the socket lock when we perform the test and set, but
427df3c68e4SRobert Watson 	 * have to release it as the pcb code needs to acquire the pcb lock,
428df3c68e4SRobert Watson 	 * which will precede the socket lock in the lock order.  However,
429df3c68e4SRobert Watson 	 * this is fine, as any race will simply result in the inpcb being
430df3c68e4SRobert Watson 	 * refreshed twice, but still consistently, as the inpcb code will
431df3c68e4SRobert Watson 	 * acquire the socket lock before refreshing, holding both locks.
432310e7cebSRobert Watson 	 */
433310e7cebSRobert Watson 	SOCK_LOCK(so);
43430d239bcSRobert Watson 	error = mac_socket_check_relabel(cred, so, label);
435310e7cebSRobert Watson 	if (error) {
436310e7cebSRobert Watson 		SOCK_UNLOCK(so);
437c66b4d8dSRobert Watson 		return (error);
438310e7cebSRobert Watson 	}
439c66b4d8dSRobert Watson 
44030d239bcSRobert Watson 	mac_socket_relabel(cred, so, label);
441310e7cebSRobert Watson 	SOCK_UNLOCK(so);
442df3c68e4SRobert Watson 
443c66b4d8dSRobert Watson 	/*
444c66b4d8dSRobert Watson 	 * If the protocol has expressed interest in socket layer changes,
445df3c68e4SRobert Watson 	 * such as if it needs to propagate changes to a cached pcb label
446df3c68e4SRobert Watson 	 * from the socket, notify it of the label change while holding the
447df3c68e4SRobert Watson 	 * socket lock.
448c66b4d8dSRobert Watson 	 */
449c66b4d8dSRobert Watson 	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
450c66b4d8dSRobert Watson 		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
451c66b4d8dSRobert Watson 
452c66b4d8dSRobert Watson 	return (0);
453c66b4d8dSRobert Watson }
454c66b4d8dSRobert Watson 
455c66b4d8dSRobert Watson int
456c66b4d8dSRobert Watson mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
457c66b4d8dSRobert Watson {
458c66b4d8dSRobert Watson 	struct label *intlabel;
459c66b4d8dSRobert Watson 	char *buffer;
460c66b4d8dSRobert Watson 	int error;
461c66b4d8dSRobert Watson 
462c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
463c66b4d8dSRobert Watson 	if (error)
464c66b4d8dSRobert Watson 		return (error);
465c66b4d8dSRobert Watson 
466c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
467c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
468c66b4d8dSRobert Watson 	if (error) {
469c66b4d8dSRobert Watson 		free(buffer, M_MACTEMP);
470c66b4d8dSRobert Watson 		return (error);
471c66b4d8dSRobert Watson 	}
472c66b4d8dSRobert Watson 
473c66b4d8dSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
47430d239bcSRobert Watson 	error = mac_socket_internalize_label(intlabel, buffer);
475c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
476c66b4d8dSRobert Watson 	if (error)
477c66b4d8dSRobert Watson 		goto out;
478c66b4d8dSRobert Watson 
479c66b4d8dSRobert Watson 	error = mac_socket_label_set(cred, so, intlabel);
480c66b4d8dSRobert Watson out:
481c66b4d8dSRobert Watson 	mac_socket_label_free(intlabel);
482c66b4d8dSRobert Watson 	return (error);
483c66b4d8dSRobert Watson }
484c66b4d8dSRobert Watson 
485c66b4d8dSRobert Watson int
486c66b4d8dSRobert Watson mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
487c66b4d8dSRobert Watson {
488c66b4d8dSRobert Watson 	char *buffer, *elements;
489310e7cebSRobert Watson 	struct label *intlabel;
490c66b4d8dSRobert Watson 	int error;
491c66b4d8dSRobert Watson 
492c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
493c66b4d8dSRobert Watson 	if (error)
494c66b4d8dSRobert Watson 		return (error);
495c66b4d8dSRobert Watson 
496c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
497c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
498c66b4d8dSRobert Watson 	if (error) {
499c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
500c66b4d8dSRobert Watson 		return (error);
501c66b4d8dSRobert Watson 	}
502c66b4d8dSRobert Watson 
503c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
504310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
505310e7cebSRobert Watson 	SOCK_LOCK(so);
50630d239bcSRobert Watson 	mac_socket_copy_label(so->so_label, intlabel);
507310e7cebSRobert Watson 	SOCK_UNLOCK(so);
50830d239bcSRobert Watson 	error = mac_socket_externalize_label(intlabel, elements, buffer,
509310e7cebSRobert Watson 	    mac->m_buflen);
510310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
511c66b4d8dSRobert Watson 	if (error == 0)
512c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
513c66b4d8dSRobert Watson 
514c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
515c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
516c66b4d8dSRobert Watson 
517c66b4d8dSRobert Watson 	return (error);
518c66b4d8dSRobert Watson }
519c66b4d8dSRobert Watson 
520c66b4d8dSRobert Watson int
521c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
522c66b4d8dSRobert Watson     struct mac *mac)
523c66b4d8dSRobert Watson {
524c66b4d8dSRobert Watson 	char *elements, *buffer;
525310e7cebSRobert Watson 	struct label *intlabel;
526c66b4d8dSRobert Watson 	int error;
527c66b4d8dSRobert Watson 
528c66b4d8dSRobert Watson 	error = mac_check_structmac_consistent(mac);
529c66b4d8dSRobert Watson 	if (error)
530c66b4d8dSRobert Watson 		return (error);
531c66b4d8dSRobert Watson 
532c66b4d8dSRobert Watson 	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
533c66b4d8dSRobert Watson 	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
534c66b4d8dSRobert Watson 	if (error) {
535c66b4d8dSRobert Watson 		free(elements, M_MACTEMP);
536c66b4d8dSRobert Watson 		return (error);
537c66b4d8dSRobert Watson 	}
538c66b4d8dSRobert Watson 
539c66b4d8dSRobert Watson 	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
540310e7cebSRobert Watson 	intlabel = mac_socket_label_alloc(M_WAITOK);
541310e7cebSRobert Watson 	SOCK_LOCK(so);
54230d239bcSRobert Watson 	mac_socket_copy_label(so->so_peerlabel, intlabel);
543310e7cebSRobert Watson 	SOCK_UNLOCK(so);
54430d239bcSRobert Watson 	error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
545310e7cebSRobert Watson 	    mac->m_buflen);
546310e7cebSRobert Watson 	mac_socket_label_free(intlabel);
547c66b4d8dSRobert Watson 	if (error == 0)
548c66b4d8dSRobert Watson 		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
549c66b4d8dSRobert Watson 
550c66b4d8dSRobert Watson 	free(buffer, M_MACTEMP);
551c66b4d8dSRobert Watson 	free(elements, M_MACTEMP);
552c66b4d8dSRobert Watson 
553c66b4d8dSRobert Watson 	return (error);
554c66b4d8dSRobert Watson }
555