1/*-
2 * Copyright (c) 1999-2002, 2007, 2009, 2019 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
5 * Copyright (c) 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 Network
13 * Associates Laboratories, the Security Research Division of Network
14 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15 * as part of the 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/sbuf.h>
56#include <sys/sdt.h>
57#include <sys/systm.h>
58#include <sys/mount.h>
59#include <sys/file.h>
60#include <sys/namei.h>
61#include <sys/protosw.h>
62#include <sys/socket.h>
63#include <sys/socketvar.h>
64#include <sys/sysctl.h>
65
66#include <net/if.h>
67#include <net/if_var.h>
68
69#include <netinet/in.h>
70#include <netinet/in_pcb.h>
71#include <netinet/ip_var.h>
72
73#include <security/mac/mac_framework.h>
74#include <security/mac/mac_internal.h>
75#include <security/mac/mac_policy.h>
76
77static struct label *
78mac_inpcb_label_alloc(int flag)
79{
80	struct label *label;
81	int error;
82
83	label = mac_labelzone_alloc(flag);
84	if (label == NULL)
85		return (NULL);
86	if (flag & M_WAITOK)
87		MAC_POLICY_CHECK(inpcb_init_label, label, flag);
88	else
89		MAC_POLICY_CHECK_NOSLEEP(inpcb_init_label, label, flag);
90	if (error) {
91		MAC_POLICY_PERFORM_NOSLEEP(inpcb_destroy_label, label);
92		mac_labelzone_free(label);
93		return (NULL);
94	}
95	return (label);
96}
97
98int
99mac_inpcb_init(struct inpcb *inp, int flag)
100{
101
102	if (mac_labeled & MPC_OBJECT_INPCB) {
103		inp->inp_label = mac_inpcb_label_alloc(flag);
104		if (inp->inp_label == NULL)
105			return (ENOMEM);
106	} else
107		inp->inp_label = NULL;
108	return (0);
109}
110
111static struct label *
112mac_ipq_label_alloc(int flag)
113{
114	struct label *label;
115	int error;
116
117	label = mac_labelzone_alloc(flag);
118	if (label == NULL)
119		return (NULL);
120
121	if (flag & M_WAITOK)
122		MAC_POLICY_CHECK(ipq_init_label, label, flag);
123	else
124		MAC_POLICY_CHECK_NOSLEEP(ipq_init_label, label, flag);
125	if (error) {
126		MAC_POLICY_PERFORM_NOSLEEP(ipq_destroy_label, label);
127		mac_labelzone_free(label);
128		return (NULL);
129	}
130	return (label);
131}
132
133int
134mac_ipq_init(struct ipq *q, int flag)
135{
136
137	if (mac_labeled & MPC_OBJECT_IPQ) {
138		q->ipq_label = mac_ipq_label_alloc(flag);
139		if (q->ipq_label == NULL)
140			return (ENOMEM);
141	} else
142		q->ipq_label = NULL;
143	return (0);
144}
145
146static void
147mac_inpcb_label_free(struct label *label)
148{
149
150	MAC_POLICY_PERFORM_NOSLEEP(inpcb_destroy_label, label);
151	mac_labelzone_free(label);
152}
153
154void
155mac_inpcb_destroy(struct inpcb *inp)
156{
157
158	if (inp->inp_label != NULL) {
159		mac_inpcb_label_free(inp->inp_label);
160		inp->inp_label = NULL;
161	}
162}
163
164static void
165mac_ipq_label_free(struct label *label)
166{
167
168	MAC_POLICY_PERFORM_NOSLEEP(ipq_destroy_label, label);
169	mac_labelzone_free(label);
170}
171
172void
173mac_ipq_destroy(struct ipq *q)
174{
175
176	if (q->ipq_label != NULL) {
177		mac_ipq_label_free(q->ipq_label);
178		q->ipq_label = NULL;
179	}
180}
181
182void
183mac_inpcb_create(struct socket *so, struct inpcb *inp)
184{
185
186	MAC_POLICY_PERFORM_NOSLEEP(inpcb_create, so, so->so_label, inp,
187	    inp->inp_label);
188}
189
190void
191mac_ipq_reassemble(struct ipq *q, struct mbuf *m)
192{
193	struct label *label;
194
195	if (mac_policy_count == 0)
196		return;
197
198	label = mac_mbuf_to_label(m);
199
200	MAC_POLICY_PERFORM_NOSLEEP(ipq_reassemble, q, q->ipq_label, m,
201	    label);
202}
203
204void
205mac_netinet_fragment(struct mbuf *m, struct mbuf *frag)
206{
207	struct label *mlabel, *fraglabel;
208
209	if (mac_policy_count == 0)
210		return;
211
212	mlabel = mac_mbuf_to_label(m);
213	fraglabel = mac_mbuf_to_label(frag);
214
215	MAC_POLICY_PERFORM_NOSLEEP(netinet_fragment, m, mlabel, frag,
216	    fraglabel);
217}
218
219void
220mac_ipq_create(struct mbuf *m, struct ipq *q)
221{
222	struct label *label;
223
224	if (mac_policy_count == 0)
225		return;
226
227	label = mac_mbuf_to_label(m);
228
229	MAC_POLICY_PERFORM_NOSLEEP(ipq_create, m, label, q, q->ipq_label);
230}
231
232void
233mac_inpcb_create_mbuf(struct inpcb *inp, struct mbuf *m)
234{
235	struct label *mlabel;
236
237	INP_LOCK_ASSERT(inp);
238
239	if (mac_policy_count == 0)
240		return;
241
242	mlabel = mac_mbuf_to_label(m);
243
244	MAC_POLICY_PERFORM_NOSLEEP(inpcb_create_mbuf, inp, inp->inp_label, m,
245	    mlabel);
246}
247
248int
249mac_ipq_match(struct mbuf *m, struct ipq *q)
250{
251	struct label *label;
252	int result;
253
254	if (mac_policy_count == 0)
255		return (1);
256
257	label = mac_mbuf_to_label(m);
258
259	result = 1;
260	MAC_POLICY_BOOLEAN_NOSLEEP(ipq_match, &&, m, label, q, q->ipq_label);
261
262	return (result);
263}
264
265void
266mac_netinet_arp_send(struct ifnet *ifp, struct mbuf *m)
267{
268	struct label *mlabel;
269	int locked;
270
271	if (mac_policy_count == 0)
272		return;
273
274	mlabel = mac_mbuf_to_label(m);
275
276	MAC_IFNET_LOCK(ifp, locked);
277	MAC_POLICY_PERFORM_NOSLEEP(netinet_arp_send, ifp, ifp->if_label, m,
278	    mlabel);
279	MAC_IFNET_UNLOCK(ifp, locked);
280}
281
282void
283mac_netinet_icmp_reply(struct mbuf *mrecv, struct mbuf *msend)
284{
285	struct label *mrecvlabel, *msendlabel;
286
287	if (mac_policy_count == 0)
288		return;
289
290	mrecvlabel = mac_mbuf_to_label(mrecv);
291	msendlabel = mac_mbuf_to_label(msend);
292
293	MAC_POLICY_PERFORM_NOSLEEP(netinet_icmp_reply, mrecv, mrecvlabel,
294	    msend, msendlabel);
295}
296
297void
298mac_netinet_icmp_replyinplace(struct mbuf *m)
299{
300	struct label *label;
301
302	if (mac_policy_count == 0)
303		return;
304
305	label = mac_mbuf_to_label(m);
306
307	MAC_POLICY_PERFORM_NOSLEEP(netinet_icmp_replyinplace, m, label);
308}
309
310void
311mac_netinet_igmp_send(struct ifnet *ifp, struct mbuf *m)
312{
313	struct label *mlabel;
314	int locked;
315
316	if (mac_policy_count == 0)
317		return;
318
319	mlabel = mac_mbuf_to_label(m);
320
321	MAC_IFNET_LOCK(ifp, locked);
322	MAC_POLICY_PERFORM_NOSLEEP(netinet_igmp_send, ifp, ifp->if_label, m,
323	    mlabel);
324	MAC_IFNET_UNLOCK(ifp, locked);
325}
326
327void
328mac_netinet_tcp_reply(struct mbuf *m)
329{
330	struct label *label;
331
332	if (mac_policy_count == 0)
333		return;
334
335	label = mac_mbuf_to_label(m);
336
337	MAC_POLICY_PERFORM_NOSLEEP(netinet_tcp_reply, m, label);
338}
339
340void
341mac_ipq_update(struct mbuf *m, struct ipq *q)
342{
343	struct label *label;
344
345	if (mac_policy_count == 0)
346		return;
347
348	label = mac_mbuf_to_label(m);
349
350	MAC_POLICY_PERFORM_NOSLEEP(ipq_update, m, label, q, q->ipq_label);
351}
352
353MAC_CHECK_PROBE_DEFINE2(inpcb_check_deliver, "struct inpcb *",
354    "struct mbuf *");
355
356int
357mac_inpcb_check_deliver(struct inpcb *inp, struct mbuf *m)
358{
359	struct label *label;
360	int error;
361
362	M_ASSERTPKTHDR(m);
363
364	if (mac_policy_count == 0)
365		return (0);
366
367	label = mac_mbuf_to_label(m);
368
369	MAC_POLICY_CHECK_NOSLEEP(inpcb_check_deliver, inp, inp->inp_label, m,
370	    label);
371	MAC_CHECK_PROBE2(inpcb_check_deliver, error, inp, m);
372
373	return (error);
374}
375
376MAC_CHECK_PROBE_DEFINE2(inpcb_check_visible, "struct ucred *",
377    "struct inpcb *");
378
379int
380mac_inpcb_check_visible(struct ucred *cred, struct inpcb *inp)
381{
382	int error;
383
384	INP_LOCK_ASSERT(inp);
385
386	MAC_POLICY_CHECK_NOSLEEP(inpcb_check_visible, cred, inp,
387	    inp->inp_label);
388	MAC_CHECK_PROBE2(inpcb_check_visible, error, cred, inp);
389
390	return (error);
391}
392
393void
394mac_inpcb_sosetlabel(struct socket *so, struct inpcb *inp)
395{
396
397	INP_WLOCK_ASSERT(inp);
398	SOCK_LOCK_ASSERT(so);
399
400	MAC_POLICY_PERFORM_NOSLEEP(inpcb_sosetlabel, so, so->so_label, inp,
401	    inp->inp_label);
402}
403
404void
405mac_netinet_firewall_reply(struct mbuf *mrecv, struct mbuf *msend)
406{
407	struct label *mrecvlabel, *msendlabel;
408
409	M_ASSERTPKTHDR(mrecv);
410	M_ASSERTPKTHDR(msend);
411
412	if (mac_policy_count == 0)
413		return;
414
415	mrecvlabel = mac_mbuf_to_label(mrecv);
416	msendlabel = mac_mbuf_to_label(msend);
417
418	MAC_POLICY_PERFORM_NOSLEEP(netinet_firewall_reply, mrecv, mrecvlabel,
419	    msend, msendlabel);
420}
421
422void
423mac_netinet_firewall_send(struct mbuf *m)
424{
425	struct label *label;
426
427	M_ASSERTPKTHDR(m);
428
429	if (mac_policy_count == 0)
430		return;
431
432	label = mac_mbuf_to_label(m);
433
434	MAC_POLICY_PERFORM_NOSLEEP(netinet_firewall_send, m, label);
435}
436
437/*
438 * These functions really should be referencing the syncache structure
439 * instead of the label.  However, due to some of the complexities associated
440 * with exposing this syncache structure we operate directly on its label
441 * pointer.  This should be OK since we aren't making any access control
442 * decisions within this code directly, we are merely allocating and copying
443 * label storage so we can properly initialize mbuf labels for any packets
444 * the syncache code might create.
445 */
446void
447mac_syncache_destroy(struct label **label)
448{
449
450	if (*label != NULL) {
451		MAC_POLICY_PERFORM_NOSLEEP(syncache_destroy_label, *label);
452		mac_labelzone_free(*label);
453		*label = NULL;
454	}
455}
456
457int
458mac_syncache_init(struct label **label)
459{
460	int error;
461
462	if (mac_labeled & MPC_OBJECT_SYNCACHE) {
463		*label = mac_labelzone_alloc(M_NOWAIT);
464		if (*label == NULL)
465			return (ENOMEM);
466		/*
467		 * Since we are holding the inpcb locks the policy can not
468		 * allocate policy specific label storage using M_WAITOK.  So
469		 * we need to do a MAC_CHECK instead of the typical
470		 * MAC_PERFORM so we can propagate allocation failures back
471		 * to the syncache code.
472		 */
473		MAC_POLICY_CHECK_NOSLEEP(syncache_init_label, *label,
474		    M_NOWAIT);
475		if (error) {
476			MAC_POLICY_PERFORM_NOSLEEP(syncache_destroy_label,
477			    *label);
478			mac_labelzone_free(*label);
479		}
480		return (error);
481	} else
482		*label = NULL;
483	return (0);
484}
485
486void
487mac_syncache_create(struct label *label, struct inpcb *inp)
488{
489
490	INP_WLOCK_ASSERT(inp);
491
492	MAC_POLICY_PERFORM_NOSLEEP(syncache_create, label, inp);
493}
494
495void
496mac_syncache_create_mbuf(struct label *sc_label, struct mbuf *m)
497{
498	struct label *mlabel;
499
500	M_ASSERTPKTHDR(m);
501
502	if (mac_policy_count == 0)
503		return;
504
505	mlabel = mac_mbuf_to_label(m);
506
507	MAC_POLICY_PERFORM_NOSLEEP(syncache_create_mbuf, sc_label, m,
508	    mlabel);
509}
510