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