1/*-
2 * Copyright (c) 1999-2002, 2009 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5 * Copyright (c) 2005-2006 SPARTA, Inc.
6 * Copyright (c) 2008 Apple Inc.
7 * All rights reserved.
8 *
9 * This software was developed by Robert Watson and Ilmar Habibulin for the
10 * TrustedBSD Project.
11 *
12 * This software was developed for the FreeBSD Project in part by McAfee
13 * Research, the Technology Research Division of Network Associates, Inc.
14 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
15 * DARPA CHATS research program.
16 *
17 * This software was enhanced by SPARTA ISSO under SPAWAR contract
18 * N66001-04-C-6019 ("SEFOS").
19 *
20 * This software was developed at the University of Cambridge Computer
21 * Laboratory with support from a grant from Google, Inc.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 */
44
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD$");
47
48#include "opt_mac.h"
49
50#include <sys/param.h>
51#include <sys/kernel.h>
52#include <sys/lock.h>
53#include <sys/malloc.h>
54#include <sys/mutex.h>
55#include <sys/mac.h>
56#include <sys/sbuf.h>
57#include <sys/sdt.h>
58#include <sys/systm.h>
59#include <sys/mount.h>
60#include <sys/file.h>
61#include <sys/namei.h>
62#include <sys/protosw.h>
63#include <sys/socket.h>
64#include <sys/socketvar.h>
65#include <sys/sysctl.h>
66
67#include <net/bpfdesc.h>
68#include <net/if.h>
69#include <net/if_var.h>
70
71#include <netinet/in.h>
72#include <netinet/in_pcb.h>
73#include <netinet/ip_var.h>
74
75#include <security/mac/mac_framework.h>
76#include <security/mac/mac_internal.h>
77#include <security/mac/mac_policy.h>
78
79/*
80 * Currently, sockets hold two labels: the label of the socket itself, and a
81 * peer label, which may be used by policies to hold a copy of the label of
82 * any remote endpoint.
83 *
84 * Possibly, this peer label should be maintained at the protocol layer
85 * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
86 * the label consistently.  For example, it might be copied live from a
87 * remote socket for UNIX domain sockets rather than keeping a local copy on
88 * this endpoint, but be cached and updated based on packets received for
89 * TCP/IP.
90 *
91 * Unlike with many other object types, the lock protecting MAC labels on
92 * sockets (the socket lock) is not frequently held at the points in code
93 * where socket-related checks are called.  The MAC Framework acquires the
94 * lock over some entry points in order to enforce atomicity (such as label
95 * copies) but in other cases the policy modules will have to acquire the
96 * lock themselves if they use labels.  This approach (a) avoids lock
97 * acquisitions when policies don't require labels and (b) solves a number of
98 * potential lock order issues when multiple sockets are used in the same
99 * entry point.
100 */
101
102struct label *
103mac_socket_label_alloc(int flag)
104{
105	struct label *label;
106	int error;
107
108	label = mac_labelzone_alloc(flag);
109	if (label == NULL)
110		return (NULL);
111
112	if (flag & M_WAITOK)
113		MAC_POLICY_CHECK(socket_init_label, label, flag);
114	else
115		MAC_POLICY_CHECK_NOSLEEP(socket_init_label, label, flag);
116	if (error) {
117		MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
118		mac_labelzone_free(label);
119		return (NULL);
120	}
121	return (label);
122}
123
124static struct label *
125mac_socketpeer_label_alloc(int flag)
126{
127	struct label *label;
128	int error;
129
130	label = mac_labelzone_alloc(flag);
131	if (label == NULL)
132		return (NULL);
133
134	if (flag & M_WAITOK)
135		MAC_POLICY_CHECK(socketpeer_init_label, label, flag);
136	else
137		MAC_POLICY_CHECK_NOSLEEP(socketpeer_init_label, label, flag);
138	if (error) {
139		MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
140		mac_labelzone_free(label);
141		return (NULL);
142	}
143	return (label);
144}
145
146int
147mac_socket_init(struct socket *so, int flag)
148{
149
150	if (mac_labeled & MPC_OBJECT_SOCKET) {
151		so->so_label = mac_socket_label_alloc(flag);
152		if (so->so_label == NULL)
153			return (ENOMEM);
154		so->so_peerlabel = mac_socketpeer_label_alloc(flag);
155		if (so->so_peerlabel == NULL) {
156			mac_socket_label_free(so->so_label);
157			so->so_label = NULL;
158			return (ENOMEM);
159		}
160	} else {
161		so->so_label = NULL;
162		so->so_peerlabel = NULL;
163	}
164	return (0);
165}
166
167void
168mac_socket_label_free(struct label *label)
169{
170
171	MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label);
172	mac_labelzone_free(label);
173}
174
175static void
176mac_socketpeer_label_free(struct label *label)
177{
178
179	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label);
180	mac_labelzone_free(label);
181}
182
183void
184mac_socket_destroy(struct socket *so)
185{
186
187	if (so->so_label != NULL) {
188		mac_socket_label_free(so->so_label);
189		so->so_label = NULL;
190		mac_socketpeer_label_free(so->so_peerlabel);
191		so->so_peerlabel = NULL;
192	}
193}
194
195void
196mac_socket_copy_label(struct label *src, struct label *dest)
197{
198
199	MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest);
200}
201
202int
203mac_socket_externalize_label(struct label *label, char *elements,
204    char *outbuf, size_t outbuflen)
205{
206	int error;
207
208	MAC_POLICY_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
209
210	return (error);
211}
212
213static int
214mac_socketpeer_externalize_label(struct label *label, char *elements,
215    char *outbuf, size_t outbuflen)
216{
217	int error;
218
219	MAC_POLICY_EXTERNALIZE(socketpeer, label, elements, outbuf,
220	    outbuflen);
221
222	return (error);
223}
224
225int
226mac_socket_internalize_label(struct label *label, char *string)
227{
228	int error;
229
230	MAC_POLICY_INTERNALIZE(socket, label, string);
231
232	return (error);
233}
234
235void
236mac_socket_create(struct ucred *cred, struct socket *so)
237{
238
239	MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label);
240}
241
242void
243mac_socket_newconn(struct socket *oldso, struct socket *newso)
244{
245
246	MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label,
247	    newso, newso->so_label);
248}
249
250static void
251mac_socket_relabel(struct ucred *cred, struct socket *so,
252    struct label *newlabel)
253{
254
255	SOCK_LOCK_ASSERT(so);
256
257	MAC_POLICY_PERFORM_NOSLEEP(socket_relabel, cred, so, so->so_label,
258	    newlabel);
259}
260
261void
262mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
263{
264	struct label *label;
265
266	if (mac_policy_count == 0)
267		return;
268
269	label = mac_mbuf_to_label(m);
270
271	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so,
272	    so->so_peerlabel);
273}
274
275void
276mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
277{
278
279	if (mac_policy_count == 0)
280		return;
281
282	MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso,
283	    oldso->so_label, newso, newso->so_peerlabel);
284}
285
286void
287mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
288{
289	struct label *label;
290
291	if (mac_policy_count == 0)
292		return;
293
294	label = mac_mbuf_to_label(m);
295
296	MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m,
297	    label);
298}
299
300MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *",
301    "struct socket *");
302
303int
304mac_socket_check_accept(struct ucred *cred, struct socket *so)
305{
306	int error;
307
308	MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so,
309	    so->so_label);
310	MAC_CHECK_PROBE2(socket_check_accept, error, cred, so);
311
312	return (error);
313}
314
315MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *",
316    "struct socket *", "struct sockaddr *");
317
318int
319mac_socket_check_bind(struct ucred *cred, struct socket *so,
320    struct sockaddr *sa)
321{
322	int error;
323
324	MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label,
325	    sa);
326	MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa);
327
328	return (error);
329}
330
331MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *",
332    "struct socket *", "struct sockaddr *");
333
334int
335mac_socket_check_connect(struct ucred *cred, struct socket *so,
336    struct sockaddr *sa)
337{
338	int error;
339
340	MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so,
341	    so->so_label, sa);
342	MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa);
343
344	return (error);
345}
346
347MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int",
348    "int");
349
350int
351mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
352{
353	int error;
354
355	MAC_POLICY_CHECK_NOSLEEP(socket_check_create, cred, domain, type,
356	    proto);
357	MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type,
358	    proto);
359
360	return (error);
361}
362
363MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *",
364    "struct mbuf *");
365
366int
367mac_socket_check_deliver(struct socket *so, struct mbuf *m)
368{
369	struct label *label;
370	int error;
371
372	if (mac_policy_count == 0)
373		return (0);
374
375	label = mac_mbuf_to_label(m);
376
377	MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m,
378	    label);
379	MAC_CHECK_PROBE2(socket_check_deliver, error, so, m);
380
381	return (error);
382}
383
384MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *",
385    "struct socket *");
386
387int
388mac_socket_check_listen(struct ucred *cred, struct socket *so)
389{
390	int error;
391
392	MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so,
393	    so->so_label);
394	MAC_CHECK_PROBE2(socket_check_listen, error, cred, so);
395
396	return (error);
397}
398
399MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *",
400    "struct socket *");
401
402int
403mac_socket_check_poll(struct ucred *cred, struct socket *so)
404{
405	int error;
406
407	MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label);
408	MAC_CHECK_PROBE2(socket_check_poll, error, cred, so);
409
410	return (error);
411}
412
413MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *",
414    "struct socket *");
415
416int
417mac_socket_check_receive(struct ucred *cred, struct socket *so)
418{
419	int error;
420
421	MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so,
422	    so->so_label);
423	MAC_CHECK_PROBE2(socket_check_receive, error, cred, so);
424
425	return (error);
426}
427
428MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *",
429    "struct socket *", "struct label *");
430
431static int
432mac_socket_check_relabel(struct ucred *cred, struct socket *so,
433    struct label *newlabel)
434{
435	int error;
436
437	SOCK_LOCK_ASSERT(so);
438
439	MAC_POLICY_CHECK_NOSLEEP(socket_check_relabel, cred, so,
440	    so->so_label, newlabel);
441	MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel);
442
443	return (error);
444}
445
446MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *",
447    "struct socket *");
448
449int
450mac_socket_check_send(struct ucred *cred, struct socket *so)
451{
452	int error;
453
454	MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label);
455	MAC_CHECK_PROBE2(socket_check_send, error, cred, so);
456
457	return (error);
458}
459
460MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *",
461    "struct socket *");
462
463int
464mac_socket_check_stat(struct ucred *cred, struct socket *so)
465{
466	int error;
467
468	MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label);
469	MAC_CHECK_PROBE2(socket_check_stat, error, cred, so);
470
471	return (error);
472}
473
474MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *",
475    "struct socket *");
476
477int
478mac_socket_check_visible(struct ucred *cred, struct socket *so)
479{
480	int error;
481
482	MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so,
483	    so->so_label);
484	MAC_CHECK_PROBE2(socket_check_visible, error, cred, so);
485
486	return (error);
487}
488
489int
490mac_socket_label_set(struct ucred *cred, struct socket *so,
491    struct label *label)
492{
493	int error;
494
495	/*
496	 * We acquire the socket lock when we perform the test and set, but
497	 * have to release it as the pcb code needs to acquire the pcb lock,
498	 * which will precede the socket lock in the lock order.  However,
499	 * this is fine, as any race will simply result in the inpcb being
500	 * refreshed twice, but still consistently, as the inpcb code will
501	 * acquire the socket lock before refreshing, holding both locks.
502	 */
503	SOCK_LOCK(so);
504	error = mac_socket_check_relabel(cred, so, label);
505	if (error) {
506		SOCK_UNLOCK(so);
507		return (error);
508	}
509
510	mac_socket_relabel(cred, so, label);
511	SOCK_UNLOCK(so);
512
513	/*
514	 * If the protocol has expressed interest in socket layer changes,
515	 * such as if it needs to propagate changes to a cached pcb label
516	 * from the socket, notify it of the label change while holding the
517	 * socket lock.
518	 */
519	if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
520		(so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
521
522	return (0);
523}
524
525int
526mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
527{
528	struct label *intlabel;
529	char *buffer;
530	int error;
531
532	if (!(mac_labeled & MPC_OBJECT_SOCKET))
533		return (EINVAL);
534
535	error = mac_check_structmac_consistent(mac);
536	if (error)
537		return (error);
538
539	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
540	error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
541	if (error) {
542		free(buffer, M_MACTEMP);
543		return (error);
544	}
545
546	intlabel = mac_socket_label_alloc(M_WAITOK);
547	error = mac_socket_internalize_label(intlabel, buffer);
548	free(buffer, M_MACTEMP);
549	if (error)
550		goto out;
551
552	error = mac_socket_label_set(cred, so, intlabel);
553out:
554	mac_socket_label_free(intlabel);
555	return (error);
556}
557
558int
559mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
560{
561	char *buffer, *elements;
562	struct label *intlabel;
563	int error;
564
565	if (!(mac_labeled & MPC_OBJECT_SOCKET))
566		return (EINVAL);
567
568	error = mac_check_structmac_consistent(mac);
569	if (error)
570		return (error);
571
572	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
573	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
574	if (error) {
575		free(elements, M_MACTEMP);
576		return (error);
577	}
578
579	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
580	intlabel = mac_socket_label_alloc(M_WAITOK);
581	SOCK_LOCK(so);
582	mac_socket_copy_label(so->so_label, intlabel);
583	SOCK_UNLOCK(so);
584	error = mac_socket_externalize_label(intlabel, elements, buffer,
585	    mac->m_buflen);
586	mac_socket_label_free(intlabel);
587	if (error == 0)
588		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
589
590	free(buffer, M_MACTEMP);
591	free(elements, M_MACTEMP);
592
593	return (error);
594}
595
596int
597mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
598    struct mac *mac)
599{
600	char *elements, *buffer;
601	struct label *intlabel;
602	int error;
603
604	if (!(mac_labeled & MPC_OBJECT_SOCKET))
605		return (EINVAL);
606
607	error = mac_check_structmac_consistent(mac);
608	if (error)
609		return (error);
610
611	elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
612	error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
613	if (error) {
614		free(elements, M_MACTEMP);
615		return (error);
616	}
617
618	buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
619	intlabel = mac_socket_label_alloc(M_WAITOK);
620	SOCK_LOCK(so);
621	mac_socket_copy_label(so->so_peerlabel, intlabel);
622	SOCK_UNLOCK(so);
623	error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
624	    mac->m_buflen);
625	mac_socket_label_free(intlabel);
626	if (error == 0)
627		error = copyout(buffer, mac->m_string, strlen(buffer)+1);
628
629	free(buffer, M_MACTEMP);
630	free(elements, M_MACTEMP);
631
632	return (error);
633}
634