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$");
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 <sys/mac_policy.h>
59
60 #include <net/bpfdesc.h>
61 #include <net/if.h>
62 #include <net/if_var.h>
63
64 #include <netinet/in.h>
65 #include <netinet/in_pcb.h>
66 #include <netinet/ip_var.h>
67
68 #include <security/mac/mac_internal.h>
69
70 /*
71 * mac_enforce_socket is used by the inet code when delivering to an inpcb
72 * without hitting the socket layer, and has to be non-static for now.
73 */
74 int mac_enforce_socket = 1;
75 SYSCTL_INT(_security_mac, OID_AUTO, enforce_socket, CTLFLAG_RW,
76 &mac_enforce_socket, 0, "Enforce MAC policy on socket operations");
77 TUNABLE_INT("security.mac.enforce_socket", &mac_enforce_socket);
78
79 #ifdef MAC_DEBUG
80 static unsigned int nmacsockets;
81
82 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, sockets, CTLFLAG_RD,
83 &nmacsockets, 0, "number of sockets in use");
84 #endif
85
86 struct label *
87 mac_socket_label_alloc(int flag)
88 {
89 struct label *label;
90 int error;
91
92 label = mac_labelzone_alloc(flag);
93 if (label == NULL)
94 return (NULL);
95
96 MAC_CHECK(init_socket_label, label, flag);
97 if (error) {
98 MAC_PERFORM(destroy_socket_label, label);
99 mac_labelzone_free(label);
100 return (NULL);
101 }
102 MAC_DEBUG_COUNTER_INC(&nmacsockets);
103 return (label);
104 }
105
106 static struct label *
107 mac_socket_peer_label_alloc(int flag)
108 {
109 struct label *label;
110 int error;
111
112 label = mac_labelzone_alloc(flag);
113 if (label == NULL)
114 return (NULL);
115
116 MAC_CHECK(init_socket_peer_label, label, flag);
117 if (error) {
118 MAC_PERFORM(destroy_socket_peer_label, label);
119 mac_labelzone_free(label);
120 return (NULL);
121 }
122 MAC_DEBUG_COUNTER_INC(&nmacsockets);
123 return (label);
124 }
125
126 int
127 mac_init_socket(struct socket *so, int flag)
128 {
129
130 so->so_label = mac_socket_label_alloc(flag);
131 if (so->so_label == NULL)
132 return (ENOMEM);
133 so->so_peerlabel = mac_socket_peer_label_alloc(flag);
134 if (so->so_peerlabel == NULL) {
135 mac_socket_label_free(so->so_label);
136 so->so_label = NULL;
137 return (ENOMEM);
138 }
139 return (0);
140 }
141
142 void
143 mac_socket_label_free(struct label *label)
144 {
145
146 MAC_PERFORM(destroy_socket_label, label);
147 mac_labelzone_free(label);
148 MAC_DEBUG_COUNTER_DEC(&nmacsockets);
149 }
150
151 static void
152 mac_socket_peer_label_free(struct label *label)
153 {
154
155 MAC_PERFORM(destroy_socket_peer_label, label);
156 mac_labelzone_free(label);
157 MAC_DEBUG_COUNTER_DEC(&nmacsockets);
158 }
159
160 void
161 mac_destroy_socket(struct socket *socket)
162 {
163
164 mac_socket_label_free(socket->so_label);
165 socket->so_label = NULL;
166 mac_socket_peer_label_free(socket->so_peerlabel);
167 socket->so_peerlabel = NULL;
168 }
169
170 void
171 mac_copy_socket_label(struct label *src, struct label *dest)
172 {
173
174 MAC_PERFORM(copy_socket_label, src, dest);
175 }
176
177 int
178 mac_externalize_socket_label(struct label *label, char *elements,
179 char *outbuf, size_t outbuflen)
180 {
181 int error;
182
183 MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
184
185 return (error);
186 }
187
188 static int
189 mac_externalize_socket_peer_label(struct label *label, char *elements,
190 char *outbuf, size_t outbuflen)
191 {
192 int error;
193
194 MAC_EXTERNALIZE(socket_peer, label, elements, outbuf, outbuflen);
195
196 return (error);
197 }
198
199 int
200 mac_internalize_socket_label(struct label *label, char *string)
201 {
202 int error;
203
204 MAC_INTERNALIZE(socket, label, string);
205
206 return (error);
207 }
208
209 void
210 mac_create_socket(struct ucred *cred, struct socket *socket)
211 {
212
213 MAC_PERFORM(create_socket, cred, socket, socket->so_label);
214 }
215
216 void
217 mac_create_socket_from_socket(struct socket *oldsocket,
218 struct socket *newsocket)
219 {
220
221 SOCK_LOCK_ASSERT(oldsocket);
222 MAC_PERFORM(create_socket_from_socket, oldsocket, oldsocket->so_label,
223 newsocket, newsocket->so_label);
224 }
225
226 static void
227 mac_relabel_socket(struct ucred *cred, struct socket *socket,
228 struct label *newlabel)
229 {
230
231 SOCK_LOCK_ASSERT(socket);
232 MAC_PERFORM(relabel_socket, cred, socket, socket->so_label, newlabel);
233 }
234
235 void
236 mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket)
237 {
238 struct label *label;
239
240 SOCK_LOCK_ASSERT(socket);
241
242 label = mac_mbuf_to_label(mbuf);
243
244 MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, label, socket,
245 socket->so_peerlabel);
246 }
247
248 void
249 mac_set_socket_peer_from_socket(struct socket *oldsocket,
250 struct socket *newsocket)
251 {
252
253 /*
254 * XXXRW: only hold the socket lock on one at a time, as one
255 * socket is the original, and one is the new. However, it's
256 * called in both directions, so we can't assert the lock
257 * here currently.
258 */
259 MAC_PERFORM(set_socket_peer_from_socket, oldsocket,
260 oldsocket->so_label, newsocket, newsocket->so_peerlabel);
261 }
262
263 void
264 mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf)
265 {
266 struct label *label;
267
268 label = mac_mbuf_to_label(mbuf);
269
270 SOCK_LOCK_ASSERT(socket);
271 MAC_PERFORM(create_mbuf_from_socket, socket, socket->so_label, mbuf,
272 label);
273 }
274
275 int
276 mac_check_socket_bind(struct ucred *ucred, struct socket *socket,
277 struct sockaddr *sockaddr)
278 {
279 int error;
280
281 SOCK_LOCK_ASSERT(socket);
282
283 if (!mac_enforce_socket)
284 return (0);
285
286 MAC_CHECK(check_socket_bind, ucred, socket, socket->so_label,
287 sockaddr);
288
289 return (error);
290 }
291
292 int
293 mac_check_socket_connect(struct ucred *cred, struct socket *socket,
294 struct sockaddr *sockaddr)
295 {
296 int error;
297
298 SOCK_LOCK_ASSERT(socket);
299
300 if (!mac_enforce_socket)
301 return (0);
302
303 MAC_CHECK(check_socket_connect, cred, socket, socket->so_label,
304 sockaddr);
305
306 return (error);
307 }
308
309 int
310 mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf)
311 {
312 struct label *label;
313 int error;
314
315 SOCK_LOCK_ASSERT(socket);
316
317 if (!mac_enforce_socket)
318 return (0);
319
320 label = mac_mbuf_to_label(mbuf);
321
322 MAC_CHECK(check_socket_deliver, socket, socket->so_label, mbuf,
323 label);
324
325 return (error);
326 }
327
328 int
329 mac_check_socket_listen(struct ucred *cred, struct socket *socket)
330 {
331 int error;
332
333 SOCK_LOCK_ASSERT(socket);
334
335 if (!mac_enforce_socket)
336 return (0);
337
338 MAC_CHECK(check_socket_listen, cred, socket, socket->so_label);
339 return (error);
340 }
341
342 int
343 mac_check_socket_receive(struct ucred *cred, struct socket *so)
344 {
345 int error;
346
347 SOCK_LOCK_ASSERT(so);
348
349 if (!mac_enforce_socket)
350 return (0);
351
352 MAC_CHECK(check_socket_receive, cred, so, so->so_label);
353
354 return (error);
355 }
356
357 static int
358 mac_check_socket_relabel(struct ucred *cred, struct socket *socket,
359 struct label *newlabel)
360 {
361 int error;
362
363 SOCK_LOCK_ASSERT(socket);
364
365 MAC_CHECK(check_socket_relabel, cred, socket, socket->so_label,
366 newlabel);
367
368 return (error);
369 }
370
371 int
372 mac_check_socket_send(struct ucred *cred, struct socket *so)
373 {
374 int error;
375
376 SOCK_LOCK_ASSERT(so);
377
378 if (!mac_enforce_socket)
379 return (0);
380
381 MAC_CHECK(check_socket_send, cred, so, so->so_label);
382
383 return (error);
384 }
385
386 int
387 mac_check_socket_visible(struct ucred *cred, struct socket *socket)
388 {
389 int error;
390
391 SOCK_LOCK_ASSERT(socket);
392
393 if (!mac_enforce_socket)
394 return (0);
395
396 MAC_CHECK(check_socket_visible, cred, socket, socket->so_label);
397
398 return (error);
399 }
400
401 int
402 mac_socket_label_set(struct ucred *cred, struct socket *so,
403 struct label *label)
404 {
405 int error;
406
407 /*
408 * We acquire the socket lock when we perform the test and set,
409 * but have to release it as the pcb code needs to acquire the
410 * pcb lock, which will precede the socket lock in the lock
411 * order. However, this is fine, as any race will simply
412 * result in the inpcb being refreshed twice, but still
413 * consistently, as the inpcb code will acquire the socket lock
414 * before refreshing, holding both locks.
415 */
416 SOCK_LOCK(so);
417 error = mac_check_socket_relabel(cred, so, label);
418 if (error) {
419 SOCK_UNLOCK(so);
420 return (error);
421 }
422
423 mac_relabel_socket(cred, so, label);
424 SOCK_UNLOCK(so);
425 /*
426 * If the protocol has expressed interest in socket layer changes,
427 * such as if it needs to propagate changes to a cached pcb
428 * label from the socket, notify it of the label change while
429 * holding the socket lock.
430 */
431 if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
432 (so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
433
434 return (0);
435 }
436
437 int
438 mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
439 {
440 struct label *intlabel;
441 char *buffer;
442 int error;
443
444 error = mac_check_structmac_consistent(mac);
445 if (error)
446 return (error);
447
448 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
449 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
450 if (error) {
451 free(buffer, M_MACTEMP);
452 return (error);
453 }
454
455 intlabel = mac_socket_label_alloc(M_WAITOK);
456 error = mac_internalize_socket_label(intlabel, buffer);
457 free(buffer, M_MACTEMP);
458 if (error)
459 goto out;
460
461 error = mac_socket_label_set(cred, so, intlabel);
462 out:
463 mac_socket_label_free(intlabel);
464 return (error);
465 }
466
467 int
468 mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
469 {
470 char *buffer, *elements;
471 struct label *intlabel;
472 int error;
473
474 error = mac_check_structmac_consistent(mac);
475 if (error)
476 return (error);
477
478 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
479 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
480 if (error) {
481 free(elements, M_MACTEMP);
482 return (error);
483 }
484
485 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
486 intlabel = mac_socket_label_alloc(M_WAITOK);
487 SOCK_LOCK(so);
488 mac_copy_socket_label(so->so_label, intlabel);
489 SOCK_UNLOCK(so);
490 error = mac_externalize_socket_label(intlabel, elements, buffer,
491 mac->m_buflen);
492 mac_socket_label_free(intlabel);
493 if (error == 0)
494 error = copyout(buffer, mac->m_string, strlen(buffer)+1);
495
496 free(buffer, M_MACTEMP);
497 free(elements, M_MACTEMP);
498
499 return (error);
500 }
501
502 int
503 mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
504 struct mac *mac)
505 {
506 char *elements, *buffer;
507 struct label *intlabel;
508 int error;
509
510 error = mac_check_structmac_consistent(mac);
511 if (error)
512 return (error);
513
514 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
515 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
516 if (error) {
517 free(elements, M_MACTEMP);
518 return (error);
519 }
520
521 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
522 intlabel = mac_socket_label_alloc(M_WAITOK);
523 SOCK_LOCK(so);
524 mac_copy_socket_label(so->so_peerlabel, intlabel);
525 SOCK_UNLOCK(so);
526 error = mac_externalize_socket_peer_label(intlabel, elements, buffer,
527 mac->m_buflen);
528 mac_socket_label_free(intlabel);
529 if (error == 0)
530 error = copyout(buffer, mac->m_string, strlen(buffer)+1);
531
532 free(buffer, M_MACTEMP);
533 free(elements, M_MACTEMP);
534
535 return (error);
536 }
Cache object: 65100fe79984fce86a9c205d01f5e4bc
|