1 /*-
2 * Copyright (c) 1999-2002 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5 * Copyright (c) 2005 SPARTA, Inc.
6 * All rights reserved.
7 *
8 * This software was developed by Robert Watson and Ilmar Habibulin for the
9 * TrustedBSD Project.
10 *
11 * This software was developed for the FreeBSD Project in part by McAfee
12 * Research, the Technology Research Division of Network Associates, Inc.
13 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
14 * DARPA CHATS research program.
15 *
16 * This software was enhanced by SPARTA ISSO under SPAWAR contract
17 * N66001-04-C-6019 ("SEFOS").
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 #include "opt_mac.h"
45
46 #include <sys/param.h>
47 #include <sys/kernel.h>
48 #include <sys/lock.h>
49 #include <sys/malloc.h>
50 #include <sys/mutex.h>
51 #include <sys/mac.h>
52 #include <sys/sbuf.h>
53 #include <sys/systm.h>
54 #include <sys/mount.h>
55 #include <sys/file.h>
56 #include <sys/namei.h>
57 #include <sys/protosw.h>
58 #include <sys/socket.h>
59 #include <sys/socketvar.h>
60 #include <sys/sysctl.h>
61
62 #include <sys/mac_policy.h>
63
64 #include <net/bpfdesc.h>
65 #include <net/if.h>
66 #include <net/if_var.h>
67
68 #include <netinet/in.h>
69 #include <netinet/in_pcb.h>
70 #include <netinet/ip_var.h>
71
72 #include <security/mac/mac_internal.h>
73
74 /*
75 * mac_enforce_socket is used by the inet code when delivering to an inpcb
76 * without hitting the socket layer, and has to be non-static for now.
77 */
78 int mac_enforce_socket = 1;
79 SYSCTL_INT(_security_mac, OID_AUTO, enforce_socket, CTLFLAG_RW,
80 &mac_enforce_socket, 0, "Enforce MAC policy on socket operations");
81 TUNABLE_INT("security.mac.enforce_socket", &mac_enforce_socket);
82
83 #ifdef MAC_DEBUG
84 static unsigned int nmacsockets;
85
86 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, sockets, CTLFLAG_RD,
87 &nmacsockets, 0, "number of sockets in use");
88 #endif
89
90 struct label *
91 mac_socket_label_alloc(int flag)
92 {
93 struct label *label;
94 int error;
95
96 label = mac_labelzone_alloc(flag);
97 if (label == NULL)
98 return (NULL);
99
100 MAC_CHECK(init_socket_label, label, flag);
101 if (error) {
102 MAC_PERFORM(destroy_socket_label, label);
103 mac_labelzone_free(label);
104 return (NULL);
105 }
106 MAC_DEBUG_COUNTER_INC(&nmacsockets);
107 return (label);
108 }
109
110 static struct label *
111 mac_socket_peer_label_alloc(int flag)
112 {
113 struct label *label;
114 int error;
115
116 label = mac_labelzone_alloc(flag);
117 if (label == NULL)
118 return (NULL);
119
120 MAC_CHECK(init_socket_peer_label, label, flag);
121 if (error) {
122 MAC_PERFORM(destroy_socket_peer_label, label);
123 mac_labelzone_free(label);
124 return (NULL);
125 }
126 MAC_DEBUG_COUNTER_INC(&nmacsockets);
127 return (label);
128 }
129
130 int
131 mac_init_socket(struct socket *so, int flag)
132 {
133
134 so->so_label = mac_socket_label_alloc(flag);
135 if (so->so_label == NULL)
136 return (ENOMEM);
137 so->so_peerlabel = mac_socket_peer_label_alloc(flag);
138 if (so->so_peerlabel == NULL) {
139 mac_socket_label_free(so->so_label);
140 so->so_label = NULL;
141 return (ENOMEM);
142 }
143 return (0);
144 }
145
146 void
147 mac_socket_label_free(struct label *label)
148 {
149
150 MAC_PERFORM(destroy_socket_label, label);
151 mac_labelzone_free(label);
152 MAC_DEBUG_COUNTER_DEC(&nmacsockets);
153 }
154
155 static void
156 mac_socket_peer_label_free(struct label *label)
157 {
158
159 MAC_PERFORM(destroy_socket_peer_label, label);
160 mac_labelzone_free(label);
161 MAC_DEBUG_COUNTER_DEC(&nmacsockets);
162 }
163
164 void
165 mac_destroy_socket(struct socket *socket)
166 {
167
168 mac_socket_label_free(socket->so_label);
169 socket->so_label = NULL;
170 mac_socket_peer_label_free(socket->so_peerlabel);
171 socket->so_peerlabel = NULL;
172 }
173
174 void
175 mac_copy_socket_label(struct label *src, struct label *dest)
176 {
177
178 MAC_PERFORM(copy_socket_label, src, dest);
179 }
180
181 int
182 mac_externalize_socket_label(struct label *label, char *elements,
183 char *outbuf, size_t outbuflen)
184 {
185 int error;
186
187 MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
188
189 return (error);
190 }
191
192 static int
193 mac_externalize_socket_peer_label(struct label *label, char *elements,
194 char *outbuf, size_t outbuflen)
195 {
196 int error;
197
198 MAC_EXTERNALIZE(socket_peer, label, elements, outbuf, outbuflen);
199
200 return (error);
201 }
202
203 int
204 mac_internalize_socket_label(struct label *label, char *string)
205 {
206 int error;
207
208 MAC_INTERNALIZE(socket, label, string);
209
210 return (error);
211 }
212
213 void
214 mac_create_socket(struct ucred *cred, struct socket *socket)
215 {
216
217 MAC_PERFORM(create_socket, cred, socket, socket->so_label);
218 }
219
220 void
221 mac_create_socket_from_socket(struct socket *oldsocket,
222 struct socket *newsocket)
223 {
224
225 SOCK_LOCK_ASSERT(oldsocket);
226 MAC_PERFORM(create_socket_from_socket, oldsocket, oldsocket->so_label,
227 newsocket, newsocket->so_label);
228 }
229
230 static void
231 mac_relabel_socket(struct ucred *cred, struct socket *socket,
232 struct label *newlabel)
233 {
234
235 SOCK_LOCK_ASSERT(socket);
236 MAC_PERFORM(relabel_socket, cred, socket, socket->so_label, newlabel);
237 }
238
239 void
240 mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket)
241 {
242 struct label *label;
243
244 SOCK_LOCK_ASSERT(socket);
245
246 label = mac_mbuf_to_label(mbuf);
247
248 MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, label, socket,
249 socket->so_peerlabel);
250 }
251
252 void
253 mac_set_socket_peer_from_socket(struct socket *oldsocket,
254 struct socket *newsocket)
255 {
256
257 /*
258 * XXXRW: only hold the socket lock on one at a time, as one
259 * socket is the original, and one is the new. However, it's
260 * called in both directions, so we can't assert the lock
261 * here currently.
262 */
263 MAC_PERFORM(set_socket_peer_from_socket, oldsocket,
264 oldsocket->so_label, newsocket, newsocket->so_peerlabel);
265 }
266
267 void
268 mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf)
269 {
270 struct label *label;
271
272 label = mac_mbuf_to_label(mbuf);
273
274 SOCK_LOCK_ASSERT(socket);
275 MAC_PERFORM(create_mbuf_from_socket, socket, socket->so_label, mbuf,
276 label);
277 }
278
279 int
280 mac_check_socket_accept(struct ucred *cred, struct socket *socket)
281 {
282 int error;
283
284 SOCK_LOCK_ASSERT(socket);
285
286 if (!mac_enforce_socket)
287 return (0);
288
289 MAC_CHECK(check_socket_accept, cred, socket, socket->so_label);
290
291 return (error);
292 }
293
294 int
295 mac_check_socket_bind(struct ucred *ucred, struct socket *socket,
296 struct sockaddr *sockaddr)
297 {
298 int error;
299
300 SOCK_LOCK_ASSERT(socket);
301
302 if (!mac_enforce_socket)
303 return (0);
304
305 MAC_CHECK(check_socket_bind, ucred, socket, socket->so_label,
306 sockaddr);
307
308 return (error);
309 }
310
311 int
312 mac_check_socket_connect(struct ucred *cred, struct socket *socket,
313 struct sockaddr *sockaddr)
314 {
315 int error;
316
317 SOCK_LOCK_ASSERT(socket);
318
319 if (!mac_enforce_socket)
320 return (0);
321
322 MAC_CHECK(check_socket_connect, cred, socket, socket->so_label,
323 sockaddr);
324
325 return (error);
326 }
327
328 int
329 mac_check_socket_create(struct ucred *cred, int domain, int type,
330 int protocol)
331 {
332 int error;
333
334 if (!mac_enforce_socket)
335 return (0);
336
337 MAC_CHECK(check_socket_create, cred, domain, type, protocol);
338
339 return (error);
340 }
341
342 int
343 mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf)
344 {
345 struct label *label;
346 int error;
347
348 SOCK_LOCK_ASSERT(socket);
349
350 if (!mac_enforce_socket)
351 return (0);
352
353 label = mac_mbuf_to_label(mbuf);
354
355 MAC_CHECK(check_socket_deliver, socket, socket->so_label, mbuf,
356 label);
357
358 return (error);
359 }
360
361 int
362 mac_check_socket_listen(struct ucred *cred, struct socket *socket)
363 {
364 int error;
365
366 SOCK_LOCK_ASSERT(socket);
367
368 if (!mac_enforce_socket)
369 return (0);
370
371 MAC_CHECK(check_socket_listen, cred, socket, socket->so_label);
372 return (error);
373 }
374
375 int
376 mac_check_socket_poll(struct ucred *cred, struct socket *so)
377 {
378 int error;
379
380 SOCK_LOCK_ASSERT(so);
381
382 if (!mac_enforce_socket)
383 return (0);
384
385 MAC_CHECK(check_socket_poll, cred, so, so->so_label);
386 return (error);
387 }
388
389 int
390 mac_check_socket_receive(struct ucred *cred, struct socket *so)
391 {
392 int error;
393
394 SOCK_LOCK_ASSERT(so);
395
396 if (!mac_enforce_socket)
397 return (0);
398
399 MAC_CHECK(check_socket_receive, cred, so, so->so_label);
400
401 return (error);
402 }
403
404 static int
405 mac_check_socket_relabel(struct ucred *cred, struct socket *socket,
406 struct label *newlabel)
407 {
408 int error;
409
410 SOCK_LOCK_ASSERT(socket);
411
412 MAC_CHECK(check_socket_relabel, cred, socket, socket->so_label,
413 newlabel);
414
415 return (error);
416 }
417
418 int
419 mac_check_socket_send(struct ucred *cred, struct socket *so)
420 {
421 int error;
422
423 SOCK_LOCK_ASSERT(so);
424
425 if (!mac_enforce_socket)
426 return (0);
427
428 MAC_CHECK(check_socket_send, cred, so, so->so_label);
429
430 return (error);
431 }
432
433 int
434 mac_check_socket_stat(struct ucred *cred, struct socket *so)
435 {
436 int error;
437
438 SOCK_LOCK_ASSERT(so);
439
440 if (!mac_enforce_socket)
441 return (0);
442
443 MAC_CHECK(check_socket_stat, cred, so, so->so_label);
444
445 return (error);
446 }
447
448 int
449 mac_check_socket_visible(struct ucred *cred, struct socket *socket)
450 {
451 int error;
452
453 SOCK_LOCK_ASSERT(socket);
454
455 if (!mac_enforce_socket)
456 return (0);
457
458 MAC_CHECK(check_socket_visible, cred, socket, socket->so_label);
459
460 return (error);
461 }
462
463 int
464 mac_socket_label_set(struct ucred *cred, struct socket *so,
465 struct label *label)
466 {
467 int error;
468
469 /*
470 * We acquire the socket lock when we perform the test and set,
471 * but have to release it as the pcb code needs to acquire the
472 * pcb lock, which will precede the socket lock in the lock
473 * order. However, this is fine, as any race will simply
474 * result in the inpcb being refreshed twice, but still
475 * consistently, as the inpcb code will acquire the socket lock
476 * before refreshing, holding both locks.
477 */
478 SOCK_LOCK(so);
479 error = mac_check_socket_relabel(cred, so, label);
480 if (error) {
481 SOCK_UNLOCK(so);
482 return (error);
483 }
484
485 mac_relabel_socket(cred, so, label);
486 SOCK_UNLOCK(so);
487 /*
488 * If the protocol has expressed interest in socket layer changes,
489 * such as if it needs to propagate changes to a cached pcb
490 * label from the socket, notify it of the label change while
491 * holding the socket lock.
492 */
493 if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
494 (so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
495
496 return (0);
497 }
498
499 int
500 mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
501 {
502 struct label *intlabel;
503 char *buffer;
504 int error;
505
506 error = mac_check_structmac_consistent(mac);
507 if (error)
508 return (error);
509
510 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
511 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
512 if (error) {
513 free(buffer, M_MACTEMP);
514 return (error);
515 }
516
517 intlabel = mac_socket_label_alloc(M_WAITOK);
518 error = mac_internalize_socket_label(intlabel, buffer);
519 free(buffer, M_MACTEMP);
520 if (error)
521 goto out;
522
523 error = mac_socket_label_set(cred, so, intlabel);
524 out:
525 mac_socket_label_free(intlabel);
526 return (error);
527 }
528
529 int
530 mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
531 {
532 char *buffer, *elements;
533 struct label *intlabel;
534 int error;
535
536 error = mac_check_structmac_consistent(mac);
537 if (error)
538 return (error);
539
540 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
541 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
542 if (error) {
543 free(elements, M_MACTEMP);
544 return (error);
545 }
546
547 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
548 intlabel = mac_socket_label_alloc(M_WAITOK);
549 SOCK_LOCK(so);
550 mac_copy_socket_label(so->so_label, intlabel);
551 SOCK_UNLOCK(so);
552 error = mac_externalize_socket_label(intlabel, elements, buffer,
553 mac->m_buflen);
554 mac_socket_label_free(intlabel);
555 if (error == 0)
556 error = copyout(buffer, mac->m_string, strlen(buffer)+1);
557
558 free(buffer, M_MACTEMP);
559 free(elements, M_MACTEMP);
560
561 return (error);
562 }
563
564 int
565 mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
566 struct mac *mac)
567 {
568 char *elements, *buffer;
569 struct label *intlabel;
570 int error;
571
572 error = mac_check_structmac_consistent(mac);
573 if (error)
574 return (error);
575
576 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
577 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
578 if (error) {
579 free(elements, M_MACTEMP);
580 return (error);
581 }
582
583 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
584 intlabel = mac_socket_label_alloc(M_WAITOK);
585 SOCK_LOCK(so);
586 mac_copy_socket_label(so->so_peerlabel, intlabel);
587 SOCK_UNLOCK(so);
588 error = mac_externalize_socket_peer_label(intlabel, elements, buffer,
589 mac->m_buflen);
590 mac_socket_label_free(intlabel);
591 if (error == 0)
592 error = copyout(buffer, mac->m_string, strlen(buffer)+1);
593
594 free(buffer, M_MACTEMP);
595 free(elements, M_MACTEMP);
596
597 return (error);
598 }
Cache object: ae19f66e7750b731acb05c89411693fd
|