mac_inet.c revision 165469
1/*-
2 * Copyright (c) 1999-2002 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
5 * All rights reserved.
6 *
7 * This software was developed by Robert Watson and Ilmar Habibulin for the
8 * TrustedBSD Project.
9 *
10 * This software was developed for the FreeBSD Project in part by Network
11 * Associates Laboratories, the Security Research Division of Network
12 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13 * as part of the DARPA CHATS research program.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/security/mac/mac_inet.c 165469 2006-12-22 23:34:47Z rwatson $");
39
40#include "opt_mac.h"
41
42#include <sys/param.h>
43#include <sys/kernel.h>
44#include <sys/lock.h>
45#include <sys/malloc.h>
46#include <sys/mutex.h>
47#include <sys/mac.h>
48#include <sys/sbuf.h>
49#include <sys/systm.h>
50#include <sys/mount.h>
51#include <sys/file.h>
52#include <sys/namei.h>
53#include <sys/protosw.h>
54#include <sys/socket.h>
55#include <sys/socketvar.h>
56#include <sys/sysctl.h>
57
58#include <net/if.h>
59#include <net/if_var.h>
60
61#include <netinet/in.h>
62#include <netinet/in_pcb.h>
63#include <netinet/ip_var.h>
64
65#include <security/mac/mac_framework.h>
66#include <security/mac/mac_internal.h>
67#include <security/mac/mac_policy.h>
68
69static struct label *
70mac_inpcb_label_alloc(int flag)
71{
72	struct label *label;
73	int error;
74
75	label = mac_labelzone_alloc(flag);
76	if (label == NULL)
77		return (NULL);
78	MAC_CHECK(init_inpcb_label, label, flag);
79	if (error) {
80		MAC_PERFORM(destroy_inpcb_label, label);
81		mac_labelzone_free(label);
82		return (NULL);
83	}
84	return (label);
85}
86
87int
88mac_init_inpcb(struct inpcb *inp, int flag)
89{
90
91	inp->inp_label = mac_inpcb_label_alloc(flag);
92	if (inp->inp_label == NULL)
93		return (ENOMEM);
94	return (0);
95}
96
97static struct label *
98mac_ipq_label_alloc(int flag)
99{
100	struct label *label;
101	int error;
102
103	label = mac_labelzone_alloc(flag);
104	if (label == NULL)
105		return (NULL);
106
107	MAC_CHECK(init_ipq_label, label, flag);
108	if (error) {
109		MAC_PERFORM(destroy_ipq_label, label);
110		mac_labelzone_free(label);
111		return (NULL);
112	}
113	return (label);
114}
115
116int
117mac_init_ipq(struct ipq *ipq, int flag)
118{
119
120	ipq->ipq_label = mac_ipq_label_alloc(flag);
121	if (ipq->ipq_label == NULL)
122		return (ENOMEM);
123	return (0);
124}
125
126static void
127mac_inpcb_label_free(struct label *label)
128{
129
130	MAC_PERFORM(destroy_inpcb_label, label);
131	mac_labelzone_free(label);
132}
133
134void
135mac_destroy_inpcb(struct inpcb *inp)
136{
137
138	mac_inpcb_label_free(inp->inp_label);
139	inp->inp_label = NULL;
140}
141
142static void
143mac_ipq_label_free(struct label *label)
144{
145
146	MAC_PERFORM(destroy_ipq_label, label);
147	mac_labelzone_free(label);
148}
149
150void
151mac_destroy_ipq(struct ipq *ipq)
152{
153
154	mac_ipq_label_free(ipq->ipq_label);
155	ipq->ipq_label = NULL;
156}
157
158void
159mac_create_inpcb_from_socket(struct socket *so, struct inpcb *inp)
160{
161
162	MAC_PERFORM(create_inpcb_from_socket, so, so->so_label, inp,
163	    inp->inp_label);
164}
165
166void
167mac_create_datagram_from_ipq(struct ipq *ipq, struct mbuf *datagram)
168{
169	struct label *label;
170
171	label = mac_mbuf_to_label(datagram);
172
173	MAC_PERFORM(create_datagram_from_ipq, ipq, ipq->ipq_label,
174	    datagram, label);
175}
176
177void
178mac_create_fragment(struct mbuf *datagram, struct mbuf *fragment)
179{
180	struct label *datagramlabel, *fragmentlabel;
181
182	datagramlabel = mac_mbuf_to_label(datagram);
183	fragmentlabel = mac_mbuf_to_label(fragment);
184
185	MAC_PERFORM(create_fragment, datagram, datagramlabel, fragment,
186	    fragmentlabel);
187}
188
189void
190mac_create_ipq(struct mbuf *fragment, struct ipq *ipq)
191{
192	struct label *label;
193
194	label = mac_mbuf_to_label(fragment);
195
196	MAC_PERFORM(create_ipq, fragment, label, ipq, ipq->ipq_label);
197}
198
199void
200mac_create_mbuf_from_inpcb(struct inpcb *inp, struct mbuf *m)
201{
202	struct label *mlabel;
203
204	INP_LOCK_ASSERT(inp);
205	mlabel = mac_mbuf_to_label(m);
206
207	MAC_PERFORM(create_mbuf_from_inpcb, inp, inp->inp_label, m, mlabel);
208}
209
210int
211mac_fragment_match(struct mbuf *fragment, struct ipq *ipq)
212{
213	struct label *label;
214	int result;
215
216	label = mac_mbuf_to_label(fragment);
217
218	result = 1;
219	MAC_BOOLEAN(fragment_match, &&, fragment, label, ipq,
220	    ipq->ipq_label);
221
222	return (result);
223}
224
225void
226mac_reflect_mbuf_icmp(struct mbuf *m)
227{
228	struct label *label;
229
230	label = mac_mbuf_to_label(m);
231
232	MAC_PERFORM(reflect_mbuf_icmp, m, label);
233}
234void
235mac_reflect_mbuf_tcp(struct mbuf *m)
236{
237	struct label *label;
238
239	label = mac_mbuf_to_label(m);
240
241	MAC_PERFORM(reflect_mbuf_tcp, m, label);
242}
243
244void
245mac_update_ipq(struct mbuf *fragment, struct ipq *ipq)
246{
247	struct label *label;
248
249	label = mac_mbuf_to_label(fragment);
250
251	MAC_PERFORM(update_ipq, fragment, label, ipq, ipq->ipq_label);
252}
253
254int
255mac_check_inpcb_deliver(struct inpcb *inp, struct mbuf *m)
256{
257	struct label *label;
258	int error;
259
260	M_ASSERTPKTHDR(m);
261
262	label = mac_mbuf_to_label(m);
263
264	MAC_CHECK(check_inpcb_deliver, inp, inp->inp_label, m, label);
265
266	return (error);
267}
268
269void
270mac_inpcb_sosetlabel(struct socket *so, struct inpcb *inp)
271{
272
273	/* XXX: assert socket lock. */
274	INP_LOCK_ASSERT(inp);
275	MAC_PERFORM(inpcb_sosetlabel, so, so->so_label, inp, inp->inp_label);
276}
277
278void
279mac_create_mbuf_from_firewall(struct mbuf *m)
280{
281	struct label *label;
282
283	M_ASSERTPKTHDR(m);
284	label = mac_mbuf_to_label(m);
285	MAC_PERFORM(create_mbuf_from_firewall, m, label);
286}
287
288/*
289 * These functions really should be referencing the syncache structure
290 * instead of the label.  However, due to some of the complexities associated
291 * with exposing this syncache structure we operate directly on it's label
292 * pointer.  This should be OK since we aren't making any access control
293 * decisions within this code directly, we are merely allocating and copying
294 * label storage so we can properly initialize mbuf labels for any packets
295 * the syncache code might create.
296 */
297void
298mac_destroy_syncache(struct label **label)
299{
300
301	MAC_PERFORM(destroy_syncache_label, *label);
302	mac_labelzone_free(*label);
303	*label = NULL;
304}
305
306int
307mac_init_syncache(struct label **label)
308{
309	int error;
310
311	*label = mac_labelzone_alloc(M_NOWAIT);
312	if (*label == NULL)
313		return (ENOMEM);
314	/*
315	 * Since we are holding the inpcb locks the policy can not allocate
316	 * policy specific label storage using M_WAITOK.  So we need to do a
317	 * MAC_CHECK instead of the typical MAC_PERFORM so we can propagate
318	 * allocation failures back to the syncache code.
319	 */
320	MAC_CHECK(init_syncache_label, *label, M_NOWAIT);
321	return (error);
322}
323
324void
325mac_init_syncache_from_inpcb(struct label *label, struct inpcb *inp)
326{
327
328	INP_LOCK_ASSERT(inp);
329	MAC_PERFORM(init_syncache_from_inpcb, label, inp);
330}
331
332void
333mac_create_mbuf_from_syncache(struct label *sc_label, struct mbuf *m)
334{
335	struct label *mbuf_label;
336
337	M_ASSERTPKTHDR(m);
338	mbuf_label = mac_mbuf_to_label(m);
339	MAC_PERFORM(create_mbuf_from_syncache, sc_label, m, mbuf_label);
340}
341