1126262Srwatson/*-
2189503Srwatson * Copyright (c) 1999-2002, 2009 Robert N. M. Watson
3126262Srwatson * Copyright (c) 2001 Ilmar S. Habibulin
4145167Srwatson * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5172930Srwatson * Copyright (c) 2005-2006 SPARTA, Inc.
6182063Srwatson * Copyright (c) 2008 Apple Inc.
7126262Srwatson * All rights reserved.
8126262Srwatson *
9126262Srwatson * This software was developed by Robert Watson and Ilmar Habibulin for the
10126262Srwatson * TrustedBSD Project.
11126262Srwatson *
12145167Srwatson * This software was developed for the FreeBSD Project in part by McAfee
13145167Srwatson * Research, the Technology Research Division of Network Associates, Inc.
14145167Srwatson * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
15145167Srwatson * DARPA CHATS research program.
16165426Srwatson *
17147784Srwatson * This software was enhanced by SPARTA ISSO under SPAWAR contract
18147784Srwatson * N66001-04-C-6019 ("SEFOS").
19126262Srwatson *
20189503Srwatson * This software was developed at the University of Cambridge Computer
21189503Srwatson * Laboratory with support from a grant from Google, Inc.
22189503Srwatson *
23126262Srwatson * Redistribution and use in source and binary forms, with or without
24126262Srwatson * modification, are permitted provided that the following conditions
25126262Srwatson * are met:
26126262Srwatson * 1. Redistributions of source code must retain the above copyright
27126262Srwatson *    notice, this list of conditions and the following disclaimer.
28126262Srwatson * 2. Redistributions in binary form must reproduce the above copyright
29126262Srwatson *    notice, this list of conditions and the following disclaimer in the
30126262Srwatson *    documentation and/or other materials provided with the distribution.
31126262Srwatson *
32126262Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33126262Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34126262Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35126262Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36126262Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37126262Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38126262Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39126262Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40126262Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41126262Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42126262Srwatson * SUCH DAMAGE.
43126262Srwatson */
44126262Srwatson
45126262Srwatson#include <sys/cdefs.h>
46126262Srwatson__FBSDID("$FreeBSD$");
47126262Srwatson
48189503Srwatson#include "opt_kdtrace.h"
49126262Srwatson#include "opt_mac.h"
50126262Srwatson
51126262Srwatson#include <sys/param.h>
52126262Srwatson#include <sys/kernel.h>
53126262Srwatson#include <sys/lock.h>
54126262Srwatson#include <sys/malloc.h>
55126262Srwatson#include <sys/mutex.h>
56126262Srwatson#include <sys/mac.h>
57126262Srwatson#include <sys/sbuf.h>
58189503Srwatson#include <sys/sdt.h>
59126262Srwatson#include <sys/systm.h>
60126262Srwatson#include <sys/mount.h>
61126262Srwatson#include <sys/file.h>
62126262Srwatson#include <sys/namei.h>
63126262Srwatson#include <sys/protosw.h>
64126262Srwatson#include <sys/socket.h>
65126262Srwatson#include <sys/socketvar.h>
66126262Srwatson#include <sys/sysctl.h>
67126262Srwatson
68126262Srwatson#include <net/bpfdesc.h>
69126262Srwatson#include <net/if.h>
70126262Srwatson#include <net/if_var.h>
71126262Srwatson
72126262Srwatson#include <netinet/in.h>
73126262Srwatson#include <netinet/in_pcb.h>
74126262Srwatson#include <netinet/ip_var.h>
75126262Srwatson
76163606Srwatson#include <security/mac/mac_framework.h>
77126262Srwatson#include <security/mac/mac_internal.h>
78165469Srwatson#include <security/mac/mac_policy.h>
79126262Srwatson
80126262Srwatson/*
81165426Srwatson * Currently, sockets hold two labels: the label of the socket itself, and a
82165426Srwatson * peer label, which may be used by policies to hold a copy of the label of
83165426Srwatson * any remote endpoint.
84165426Srwatson *
85165426Srwatson * Possibly, this peer label should be maintained at the protocol layer
86165426Srwatson * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
87165426Srwatson * the label consistently.  For example, it might be copied live from a
88165426Srwatson * remote socket for UNIX domain sockets rather than keeping a local copy on
89165426Srwatson * this endpoint, but be cached and updated based on packets received for
90165426Srwatson * TCP/IP.
91193391Srwatson *
92193391Srwatson * Unlike with many other object types, the lock protecting MAC labels on
93193391Srwatson * sockets (the socket lock) is not frequently held at the points in code
94193391Srwatson * where socket-related checks are called.  The MAC Framework acquires the
95193391Srwatson * lock over some entry points in order to enforce atomicity (such as label
96193391Srwatson * copies) but in other cases the policy modules will have to acquire the
97193391Srwatson * lock themselves if they use labels.  This approach (a) avoids lock
98193391Srwatson * acquisitions when policies don't require labels and (b) solves a number of
99193391Srwatson * potential lock order issues when multiple sockets are used in the same
100193391Srwatson * entry point.
101165426Srwatson */
102165426Srwatson
103126262Srwatsonstruct label *
104126262Srwatsonmac_socket_label_alloc(int flag)
105126262Srwatson{
106126262Srwatson	struct label *label;
107126262Srwatson	int error;
108126262Srwatson
109126262Srwatson	label = mac_labelzone_alloc(flag);
110126262Srwatson	if (label == NULL)
111126262Srwatson		return (NULL);
112126262Srwatson
113189797Srwatson	if (flag & M_WAITOK)
114191731Srwatson		MAC_POLICY_CHECK(socket_init_label, label, flag);
115189797Srwatson	else
116191731Srwatson		MAC_POLICY_CHECK_NOSLEEP(socket_init_label, label, flag);
117126262Srwatson	if (error) {
118191731Srwatson		MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
119126262Srwatson		mac_labelzone_free(label);
120126262Srwatson		return (NULL);
121126262Srwatson	}
122126262Srwatson	return (label);
123126262Srwatson}
124126262Srwatson
125126262Srwatsonstatic struct label *
126172930Srwatsonmac_socketpeer_label_alloc(int flag)
127126262Srwatson{
128126262Srwatson	struct label *label;
129126262Srwatson	int error;
130126262Srwatson
131126262Srwatson	label = mac_labelzone_alloc(flag);
132126262Srwatson	if (label == NULL)
133126262Srwatson		return (NULL);
134126262Srwatson
135189797Srwatson	if (flag & M_WAITOK)
136191731Srwatson		MAC_POLICY_CHECK(socketpeer_init_label, label, flag);
137189797Srwatson	else
138191731Srwatson		MAC_POLICY_CHECK_NOSLEEP(socketpeer_init_label, label, flag);
139126262Srwatson	if (error) {
140191731Srwatson		MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
141126262Srwatson		mac_labelzone_free(label);
142126262Srwatson		return (NULL);
143126262Srwatson	}
144126262Srwatson	return (label);
145126262Srwatson}
146126262Srwatson
147126262Srwatsonint
148172930Srwatsonmac_socket_init(struct socket *so, int flag)
149126262Srwatson{
150126262Srwatson
151182063Srwatson	if (mac_labeled & MPC_OBJECT_SOCKET) {
152182063Srwatson		so->so_label = mac_socket_label_alloc(flag);
153182063Srwatson		if (so->so_label == NULL)
154182063Srwatson			return (ENOMEM);
155182063Srwatson		so->so_peerlabel = mac_socketpeer_label_alloc(flag);
156182063Srwatson		if (so->so_peerlabel == NULL) {
157182063Srwatson			mac_socket_label_free(so->so_label);
158182063Srwatson			so->so_label = NULL;
159182063Srwatson			return (ENOMEM);
160182063Srwatson		}
161182063Srwatson	} else {
162126262Srwatson		so->so_label = NULL;
163182063Srwatson		so->so_peerlabel = NULL;
164126262Srwatson	}
165126262Srwatson	return (0);
166126262Srwatson}
167126262Srwatson
168126262Srwatsonvoid
169126262Srwatsonmac_socket_label_free(struct label *label)
170126262Srwatson{
171126262Srwatson
172191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
173126262Srwatson	mac_labelzone_free(label);
174126262Srwatson}
175126262Srwatson
176126262Srwatsonstatic void
177172930Srwatsonmac_socketpeer_label_free(struct label *label)
178126262Srwatson{
179126262Srwatson
180191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
181126262Srwatson	mac_labelzone_free(label);
182126262Srwatson}
183126262Srwatson
184126262Srwatsonvoid
185172930Srwatsonmac_socket_destroy(struct socket *so)
186126262Srwatson{
187126262Srwatson
188182063Srwatson	if (so->so_label != NULL) {
189182063Srwatson		mac_socket_label_free(so->so_label);
190182063Srwatson		so->so_label = NULL;
191182063Srwatson		mac_socketpeer_label_free(so->so_peerlabel);
192182063Srwatson		so->so_peerlabel = NULL;
193182063Srwatson	}
194126262Srwatson}
195126262Srwatson
196126262Srwatsonvoid
197172930Srwatsonmac_socket_copy_label(struct label *src, struct label *dest)
198126262Srwatson{
199126262Srwatson
200191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest);
201126262Srwatson}
202126262Srwatson
203126262Srwatsonint
204172930Srwatsonmac_socket_externalize_label(struct label *label, char *elements,
205126262Srwatson    char *outbuf, size_t outbuflen)
206126262Srwatson{
207126262Srwatson	int error;
208126262Srwatson
209191731Srwatson	MAC_POLICY_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
210126262Srwatson
211126262Srwatson	return (error);
212126262Srwatson}
213126262Srwatson
214126262Srwatsonstatic int
215172930Srwatsonmac_socketpeer_externalize_label(struct label *label, char *elements,
216126262Srwatson    char *outbuf, size_t outbuflen)
217126262Srwatson{
218126262Srwatson	int error;
219126262Srwatson
220191731Srwatson	MAC_POLICY_EXTERNALIZE(socketpeer, label, elements, outbuf,
221191731Srwatson	    outbuflen);
222126262Srwatson
223126262Srwatson	return (error);
224126262Srwatson}
225126262Srwatson
226126262Srwatsonint
227172930Srwatsonmac_socket_internalize_label(struct label *label, char *string)
228126262Srwatson{
229126262Srwatson	int error;
230126262Srwatson
231191731Srwatson	MAC_POLICY_INTERNALIZE(socket, label, string);
232126262Srwatson
233126262Srwatson	return (error);
234126262Srwatson}
235126262Srwatson
236126262Srwatsonvoid
237172930Srwatsonmac_socket_create(struct ucred *cred, struct socket *so)
238126262Srwatson{
239126262Srwatson
240191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label);
241126262Srwatson}
242126262Srwatson
243126262Srwatsonvoid
244172930Srwatsonmac_socket_newconn(struct socket *oldso, struct socket *newso)
245126262Srwatson{
246126262Srwatson
247191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label,
248191731Srwatson	    newso, newso->so_label);
249126262Srwatson}
250126262Srwatson
251126262Srwatsonstatic void
252172930Srwatsonmac_socket_relabel(struct ucred *cred, struct socket *so,
253126262Srwatson    struct label *newlabel)
254126262Srwatson{
255126262Srwatson
256168955Srwatson	SOCK_LOCK_ASSERT(so);
257168955Srwatson
258191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socket_relabel, cred, so, so->so_label,
259189797Srwatson	    newlabel);
260126262Srwatson}
261126262Srwatson
262126262Srwatsonvoid
263172930Srwatsonmac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
264126262Srwatson{
265126262Srwatson	struct label *label;
266126262Srwatson
267193391Srwatson	if (mac_policy_count == 0)
268193391Srwatson		return;
269193391Srwatson
270168955Srwatson	label = mac_mbuf_to_label(m);
271126262Srwatson
272191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so,
273168955Srwatson	    so->so_peerlabel);
274126262Srwatson}
275126262Srwatson
276126262Srwatsonvoid
277172930Srwatsonmac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
278126262Srwatson{
279193332Srwatson
280193332Srwatson	if (mac_policy_count == 0)
281193332Srwatson		return;
282126262Srwatson
283191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso,
284189797Srwatson	    oldso->so_label, newso, newso->so_peerlabel);
285126262Srwatson}
286126262Srwatson
287126262Srwatsonvoid
288172930Srwatsonmac_socket_create_mbuf(struct socket *so, struct mbuf *m)
289126262Srwatson{
290126262Srwatson	struct label *label;
291126262Srwatson
292193332Srwatson	if (mac_policy_count == 0)
293193332Srwatson		return;
294126262Srwatson
295168955Srwatson	label = mac_mbuf_to_label(m);
296168955Srwatson
297191731Srwatson	MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m,
298191731Srwatson	    label);
299126262Srwatson}
300126262Srwatson
301189503SrwatsonMAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *",
302189503Srwatson    "struct socket *");
303189503Srwatson
304126262Srwatsonint
305172930Srwatsonmac_socket_check_accept(struct ucred *cred, struct socket *so)
306145167Srwatson{
307145167Srwatson	int error;
308145167Srwatson
309191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so,
310191731Srwatson	    so->so_label);
311189503Srwatson	MAC_CHECK_PROBE2(socket_check_accept, error, cred, so);
312145167Srwatson
313145167Srwatson	return (error);
314145167Srwatson}
315145167Srwatson
316189503SrwatsonMAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *",
317189503Srwatson    "struct socket *", "struct sockaddr *");
318189503Srwatson
319145167Srwatsonint
320189532Srwatsonmac_socket_check_bind(struct ucred *cred, struct socket *so,
321168955Srwatson    struct sockaddr *sa)
322126262Srwatson{
323126262Srwatson	int error;
324126262Srwatson
325191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label,
326191731Srwatson	    sa);
327189532Srwatson	MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa);
328126262Srwatson
329126262Srwatson	return (error);
330126262Srwatson}
331126262Srwatson
332189503SrwatsonMAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *",
333189503Srwatson    "struct socket *", "struct sockaddr *");
334189503Srwatson
335126262Srwatsonint
336172930Srwatsonmac_socket_check_connect(struct ucred *cred, struct socket *so,
337168955Srwatson    struct sockaddr *sa)
338126262Srwatson{
339126262Srwatson	int error;
340126262Srwatson
341191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so,
342191731Srwatson	    so->so_label, sa);
343189503Srwatson	MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa);
344126262Srwatson
345126262Srwatson	return (error);
346126262Srwatson}
347126262Srwatson
348189503SrwatsonMAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int",
349189503Srwatson    "int");
350189503Srwatson
351126262Srwatsonint
352172930Srwatsonmac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
353147784Srwatson{
354147784Srwatson	int error;
355147784Srwatson
356191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_create, cred, domain, type,
357191731Srwatson	    proto);
358189503Srwatson	MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type,
359189503Srwatson	    proto);
360147784Srwatson
361147784Srwatson	return (error);
362147784Srwatson}
363147784Srwatson
364189503SrwatsonMAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *",
365189503Srwatson    "struct mbuf *");
366189503Srwatson
367147784Srwatsonint
368172930Srwatsonmac_socket_check_deliver(struct socket *so, struct mbuf *m)
369126262Srwatson{
370126262Srwatson	struct label *label;
371126262Srwatson	int error;
372126262Srwatson
373193332Srwatson	if (mac_policy_count == 0)
374193332Srwatson		return (0);
375130398Srwatson
376168955Srwatson	label = mac_mbuf_to_label(m);
377126262Srwatson
378191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m,
379191731Srwatson	    label);
380189503Srwatson	MAC_CHECK_PROBE2(socket_check_deliver, error, so, m);
381126262Srwatson
382126262Srwatson	return (error);
383126262Srwatson}
384126262Srwatson
385189503SrwatsonMAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *",
386189503Srwatson    "struct socket *");
387189503Srwatson
388126262Srwatsonint
389172930Srwatsonmac_socket_check_listen(struct ucred *cred, struct socket *so)
390126262Srwatson{
391126262Srwatson	int error;
392126262Srwatson
393191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so,
394191731Srwatson	    so->so_label);
395189503Srwatson	MAC_CHECK_PROBE2(socket_check_listen, error, cred, so);
396168955Srwatson
397126262Srwatson	return (error);
398126262Srwatson}
399126262Srwatson
400189503SrwatsonMAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *",
401189503Srwatson    "struct socket *");
402189503Srwatson
403126262Srwatsonint
404172930Srwatsonmac_socket_check_poll(struct ucred *cred, struct socket *so)
405145167Srwatson{
406145167Srwatson	int error;
407145167Srwatson
408191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label);
409189503Srwatson	MAC_CHECK_PROBE2(socket_check_poll, error, cred, so);
410168955Srwatson
411145167Srwatson	return (error);
412145167Srwatson}
413145167Srwatson
414189503SrwatsonMAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *",
415189503Srwatson    "struct socket *");
416189503Srwatson
417145167Srwatsonint
418172930Srwatsonmac_socket_check_receive(struct ucred *cred, struct socket *so)
419126262Srwatson{
420126262Srwatson	int error;
421126262Srwatson
422191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so,
423191731Srwatson	    so->so_label);
424189503Srwatson	MAC_CHECK_PROBE2(socket_check_receive, error, cred, so);
425126262Srwatson
426126262Srwatson	return (error);
427126262Srwatson}
428126262Srwatson
429189503SrwatsonMAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *",
430189503Srwatson    "struct socket *", "struct label *");
431189503Srwatson
432126262Srwatsonstatic int
433172930Srwatsonmac_socket_check_relabel(struct ucred *cred, struct socket *so,
434126262Srwatson    struct label *newlabel)
435126262Srwatson{
436126262Srwatson	int error;
437126262Srwatson
438168955Srwatson	SOCK_LOCK_ASSERT(so);
439130398Srwatson
440191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_relabel, cred, so,
441191731Srwatson	    so->so_label, newlabel);
442189503Srwatson	MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel);
443126262Srwatson
444126262Srwatson	return (error);
445126262Srwatson}
446126262Srwatson
447189503SrwatsonMAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *",
448189503Srwatson    "struct socket *");
449189503Srwatson
450126262Srwatsonint
451172930Srwatsonmac_socket_check_send(struct ucred *cred, struct socket *so)
452126262Srwatson{
453126262Srwatson	int error;
454126262Srwatson
455191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label);
456189503Srwatson	MAC_CHECK_PROBE2(socket_check_send, error, cred, so);
457126262Srwatson
458126262Srwatson	return (error);
459126262Srwatson}
460126262Srwatson
461189503SrwatsonMAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *",
462189503Srwatson    "struct socket *");
463189503Srwatson
464126262Srwatsonint
465172930Srwatsonmac_socket_check_stat(struct ucred *cred, struct socket *so)
466145167Srwatson{
467145167Srwatson	int error;
468145167Srwatson
469191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label);
470189503Srwatson	MAC_CHECK_PROBE2(socket_check_stat, error, cred, so);
471145167Srwatson
472145167Srwatson	return (error);
473145167Srwatson}
474145167Srwatson
475189503SrwatsonMAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *",
476189503Srwatson    "struct socket *");
477189503Srwatson
478145167Srwatsonint
479172930Srwatsonmac_socket_check_visible(struct ucred *cred, struct socket *so)
480126262Srwatson{
481126262Srwatson	int error;
482126262Srwatson
483191731Srwatson	MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so,
484191731Srwatson	    so->so_label);
485189503Srwatson	MAC_CHECK_PROBE2(socket_check_visible, error, cred, so);
486126262Srwatson
487126262Srwatson	return (error);
488126262Srwatson}
489126262Srwatson
490126262Srwatsonint
491126262Srwatsonmac_socket_label_set(struct ucred *cred, struct socket *so,
492126262Srwatson    struct label *label)
493126262Srwatson{
494126262Srwatson	int error;
495126262Srwatson
496130398Srwatson	/*
497165426Srwatson	 * We acquire the socket lock when we perform the test and set, but
498165426Srwatson	 * have to release it as the pcb code needs to acquire the pcb lock,
499165426Srwatson	 * which will precede the socket lock in the lock order.  However,
500165426Srwatson	 * this is fine, as any race will simply result in the inpcb being
501165426Srwatson	 * refreshed twice, but still consistently, as the inpcb code will
502165426Srwatson	 * acquire the socket lock before refreshing, holding both locks.
503130398Srwatson	 */
504130398Srwatson	SOCK_LOCK(so);
505172930Srwatson	error = mac_socket_check_relabel(cred, so, label);
506130398Srwatson	if (error) {
507130398Srwatson		SOCK_UNLOCK(so);
508126262Srwatson		return (error);
509130398Srwatson	}
510126262Srwatson
511172930Srwatson	mac_socket_relabel(cred, so, label);
512130398Srwatson	SOCK_UNLOCK(so);
513165426Srwatson
514126262Srwatson	/*
515126262Srwatson	 * If the protocol has expressed interest in socket layer changes,
516165426Srwatson	 * such as if it needs to propagate changes to a cached pcb label
517165426Srwatson	 * from the socket, notify it of the label change while holding the
518165426Srwatson	 * socket lock.
519126262Srwatson	 */
520126262Srwatson	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
521126262Srwatson		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
522126262Srwatson
523126262Srwatson	return (0);
524126262Srwatson}
525126262Srwatson
526126262Srwatsonint
527126262Srwatsonmac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
528126262Srwatson{
529126262Srwatson	struct label *intlabel;
530126262Srwatson	char *buffer;
531126262Srwatson	int error;
532126262Srwatson
533182063Srwatson	if (!(mac_labeled & MPC_OBJECT_SOCKET))
534182063Srwatson		return (EINVAL);
535182063Srwatson
536126262Srwatson	error = mac_check_structmac_consistent(mac);
537126262Srwatson	if (error)
538126262Srwatson		return (error);
539126262Srwatson
540126262Srwatson	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
541126262Srwatson	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
542126262Srwatson	if (error) {
543126262Srwatson		free(buffer, M_MACTEMP);
544126262Srwatson		return (error);
545126262Srwatson	}
546126262Srwatson
547126262Srwatson	intlabel = mac_socket_label_alloc(M_WAITOK);
548172930Srwatson	error = mac_socket_internalize_label(intlabel, buffer);
549126262Srwatson	free(buffer, M_MACTEMP);
550126262Srwatson	if (error)
551126262Srwatson		goto out;
552126262Srwatson
553126262Srwatson	error = mac_socket_label_set(cred, so, intlabel);
554126262Srwatsonout:
555126262Srwatson	mac_socket_label_free(intlabel);
556126262Srwatson	return (error);
557126262Srwatson}
558126262Srwatson
559126262Srwatsonint
560126262Srwatsonmac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
561126262Srwatson{
562126262Srwatson	char *buffer, *elements;
563130398Srwatson	struct label *intlabel;
564126262Srwatson	int error;
565126262Srwatson
566182063Srwatson	if (!(mac_labeled & MPC_OBJECT_SOCKET))
567182063Srwatson		return (EINVAL);
568182063Srwatson
569126262Srwatson	error = mac_check_structmac_consistent(mac);
570126262Srwatson	if (error)
571126262Srwatson		return (error);
572126262Srwatson
573126262Srwatson	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
574126262Srwatson	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
575126262Srwatson	if (error) {
576126262Srwatson		free(elements, M_MACTEMP);
577126262Srwatson		return (error);
578126262Srwatson	}
579126262Srwatson
580126262Srwatson	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
581130398Srwatson	intlabel = mac_socket_label_alloc(M_WAITOK);
582130398Srwatson	SOCK_LOCK(so);
583172930Srwatson	mac_socket_copy_label(so->so_label, intlabel);
584130398Srwatson	SOCK_UNLOCK(so);
585172930Srwatson	error = mac_socket_externalize_label(intlabel, elements, buffer,
586130398Srwatson	    mac->m_buflen);
587130398Srwatson	mac_socket_label_free(intlabel);
588126262Srwatson	if (error == 0)
589126262Srwatson		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
590126262Srwatson
591126262Srwatson	free(buffer, M_MACTEMP);
592126262Srwatson	free(elements, M_MACTEMP);
593126262Srwatson
594126262Srwatson	return (error);
595126262Srwatson}
596126262Srwatson
597126262Srwatsonint
598126262Srwatsonmac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
599126262Srwatson    struct mac *mac)
600126262Srwatson{
601126262Srwatson	char *elements, *buffer;
602130398Srwatson	struct label *intlabel;
603126262Srwatson	int error;
604126262Srwatson
605182063Srwatson	if (!(mac_labeled & MPC_OBJECT_SOCKET))
606182063Srwatson		return (EINVAL);
607182063Srwatson
608126262Srwatson	error = mac_check_structmac_consistent(mac);
609126262Srwatson	if (error)
610126262Srwatson		return (error);
611126262Srwatson
612126262Srwatson	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
613126262Srwatson	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
614126262Srwatson	if (error) {
615126262Srwatson		free(elements, M_MACTEMP);
616126262Srwatson		return (error);
617126262Srwatson	}
618126262Srwatson
619126262Srwatson	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
620130398Srwatson	intlabel = mac_socket_label_alloc(M_WAITOK);
621130398Srwatson	SOCK_LOCK(so);
622172930Srwatson	mac_socket_copy_label(so->so_peerlabel, intlabel);
623130398Srwatson	SOCK_UNLOCK(so);
624172930Srwatson	error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
625130398Srwatson	    mac->m_buflen);
626130398Srwatson	mac_socket_label_free(intlabel);
627126262Srwatson	if (error == 0)
628126262Srwatson		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
629126262Srwatson
630126262Srwatson	free(buffer, M_MACTEMP);
631126262Srwatson	free(elements, M_MACTEMP);
632126262Srwatson
633126262Srwatson	return (error);
634126262Srwatson}
635