]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/security/mac/mac_socket.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / sys / security / mac / mac_socket.c
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-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 McAfee
13  * Research, the Technology Research Division of Network Associates, Inc.
14  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
15  * DARPA CHATS research program.
16  *
17  * This software was enhanced by SPARTA ISSO under SPAWAR contract
18  * N66001-04-C-6019 ("SEFOS").
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  */
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44
45 #include "opt_mac.h"
46
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/lock.h>
50 #include <sys/malloc.h>
51 #include <sys/mutex.h>
52 #include <sys/mac.h>
53 #include <sys/sbuf.h>
54 #include <sys/systm.h>
55 #include <sys/mount.h>
56 #include <sys/file.h>
57 #include <sys/namei.h>
58 #include <sys/protosw.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/sysctl.h>
62
63 #include <net/bpfdesc.h>
64 #include <net/if.h>
65 #include <net/if_var.h>
66
67 #include <netinet/in.h>
68 #include <netinet/in_pcb.h>
69 #include <netinet/ip_var.h>
70
71 #include <security/mac/mac_framework.h>
72 #include <security/mac/mac_internal.h>
73 #include <security/mac/mac_policy.h>
74
75 /*
76  * Currently, sockets hold two labels: the label of the socket itself, and a
77  * peer label, which may be used by policies to hold a copy of the label of
78  * any remote endpoint.
79  *
80  * Possibly, this peer label should be maintained at the protocol layer
81  * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
82  * the label consistently.  For example, it might be copied live from a
83  * remote socket for UNIX domain sockets rather than keeping a local copy on
84  * this endpoint, but be cached and updated based on packets received for
85  * TCP/IP.
86  */
87
88 struct label *
89 mac_socket_label_alloc(int flag)
90 {
91         struct label *label;
92         int error;
93
94         label = mac_labelzone_alloc(flag);
95         if (label == NULL)
96                 return (NULL);
97
98         MAC_CHECK(socket_init_label, label, flag);
99         if (error) {
100                 MAC_PERFORM(socket_destroy_label, label);
101                 mac_labelzone_free(label);
102                 return (NULL);
103         }
104         return (label);
105 }
106
107 static struct label *
108 mac_socketpeer_label_alloc(int flag)
109 {
110         struct label *label;
111         int error;
112
113         label = mac_labelzone_alloc(flag);
114         if (label == NULL)
115                 return (NULL);
116
117         MAC_CHECK(socketpeer_init_label, label, flag);
118         if (error) {
119                 MAC_PERFORM(socketpeer_destroy_label, label);
120                 mac_labelzone_free(label);
121                 return (NULL);
122         }
123         return (label);
124 }
125
126 int
127 mac_socket_init(struct socket *so, int flag)
128 {
129
130         if (mac_labeled & MPC_OBJECT_SOCKET) {
131                 so->so_label = mac_socket_label_alloc(flag);
132                 if (so->so_label == NULL)
133                         return (ENOMEM);
134                 so->so_peerlabel = mac_socketpeer_label_alloc(flag);
135                 if (so->so_peerlabel == NULL) {
136                         mac_socket_label_free(so->so_label);
137                         so->so_label = NULL;
138                         return (ENOMEM);
139                 }
140         } else {
141                 so->so_label = NULL;
142                 so->so_peerlabel = NULL;
143         }
144         return (0);
145 }
146
147 void
148 mac_socket_label_free(struct label *label)
149 {
150
151         MAC_PERFORM(socket_destroy_label, label);
152         mac_labelzone_free(label);
153 }
154
155 static void
156 mac_socketpeer_label_free(struct label *label)
157 {
158
159         MAC_PERFORM(socketpeer_destroy_label, label);
160         mac_labelzone_free(label);
161 }
162
163 void
164 mac_socket_destroy(struct socket *so)
165 {
166
167         if (so->so_label != NULL) {
168                 mac_socket_label_free(so->so_label);
169                 so->so_label = NULL;
170                 mac_socketpeer_label_free(so->so_peerlabel);
171                 so->so_peerlabel = NULL;
172         }
173 }
174
175 void
176 mac_socket_copy_label(struct label *src, struct label *dest)
177 {
178
179         MAC_PERFORM(socket_copy_label, src, dest);
180 }
181
182 int
183 mac_socket_externalize_label(struct label *label, char *elements,
184     char *outbuf, size_t outbuflen)
185 {
186         int error;
187
188         MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
189
190         return (error);
191 }
192
193 static int
194 mac_socketpeer_externalize_label(struct label *label, char *elements,
195     char *outbuf, size_t outbuflen)
196 {
197         int error;
198
199         MAC_EXTERNALIZE(socketpeer, label, elements, outbuf, outbuflen);
200
201         return (error);
202 }
203
204 int
205 mac_socket_internalize_label(struct label *label, char *string)
206 {
207         int error;
208
209         MAC_INTERNALIZE(socket, label, string);
210
211         return (error);
212 }
213
214 void
215 mac_socket_create(struct ucred *cred, struct socket *so)
216 {
217
218         MAC_PERFORM(socket_create, cred, so, so->so_label);
219 }
220
221 void
222 mac_socket_newconn(struct socket *oldso, struct socket *newso)
223 {
224
225         SOCK_LOCK_ASSERT(oldso);
226
227         MAC_PERFORM(socket_newconn, oldso, oldso->so_label, newso,
228             newso->so_label);
229 }
230
231 static void
232 mac_socket_relabel(struct ucred *cred, struct socket *so,
233     struct label *newlabel)
234 {
235
236         SOCK_LOCK_ASSERT(so);
237
238         MAC_PERFORM(socket_relabel, cred, so, so->so_label, newlabel);
239 }
240
241 void
242 mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
243 {
244         struct label *label;
245
246         SOCK_LOCK_ASSERT(so);
247
248         label = mac_mbuf_to_label(m);
249
250         MAC_PERFORM(socketpeer_set_from_mbuf, m, label, so,
251             so->so_peerlabel);
252 }
253
254 void
255 mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
256 {
257
258         /*
259          * XXXRW: only hold the socket lock on one at a time, as one socket
260          * is the original, and one is the new.  However, it's called in both
261          * directions, so we can't assert the lock here currently.
262          */
263         MAC_PERFORM(socketpeer_set_from_socket, oldso, oldso->so_label,
264             newso, newso->so_peerlabel);
265 }
266
267 void
268 mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
269 {
270         struct label *label;
271
272         SOCK_LOCK_ASSERT(so);
273
274         label = mac_mbuf_to_label(m);
275
276         MAC_PERFORM(socket_create_mbuf, so, so->so_label, m, label);
277 }
278
279 int
280 mac_socket_check_accept(struct ucred *cred, struct socket *so)
281 {
282         int error;
283
284         SOCK_LOCK_ASSERT(so);
285
286         MAC_CHECK(socket_check_accept, cred, so, so->so_label);
287
288         return (error);
289 }
290
291 int
292 mac_socket_check_bind(struct ucred *ucred, struct socket *so,
293     struct sockaddr *sa)
294 {
295         int error;
296
297         SOCK_LOCK_ASSERT(so);
298
299         MAC_CHECK(socket_check_bind, ucred, so, so->so_label, sa);
300
301         return (error);
302 }
303
304 int
305 mac_socket_check_connect(struct ucred *cred, struct socket *so,
306     struct sockaddr *sa)
307 {
308         int error;
309
310         SOCK_LOCK_ASSERT(so);
311
312         MAC_CHECK(socket_check_connect, cred, so, so->so_label, sa);
313
314         return (error);
315 }
316
317 int
318 mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
319 {
320         int error;
321
322         MAC_CHECK(socket_check_create, cred, domain, type, proto);
323
324         return (error);
325 }
326
327 int
328 mac_socket_check_deliver(struct socket *so, struct mbuf *m)
329 {
330         struct label *label;
331         int error;
332
333         SOCK_LOCK_ASSERT(so);
334
335         label = mac_mbuf_to_label(m);
336
337         MAC_CHECK(socket_check_deliver, so, so->so_label, m, label);
338
339         return (error);
340 }
341
342 int
343 mac_socket_check_listen(struct ucred *cred, struct socket *so)
344 {
345         int error;
346
347         SOCK_LOCK_ASSERT(so);
348
349         MAC_CHECK(socket_check_listen, cred, so, so->so_label);
350
351         return (error);
352 }
353
354 int
355 mac_socket_check_poll(struct ucred *cred, struct socket *so)
356 {
357         int error;
358
359         SOCK_LOCK_ASSERT(so);
360
361         MAC_CHECK(socket_check_poll, cred, so, so->so_label);
362
363         return (error);
364 }
365
366 int
367 mac_socket_check_receive(struct ucred *cred, struct socket *so)
368 {
369         int error;
370
371         SOCK_LOCK_ASSERT(so);
372
373         MAC_CHECK(socket_check_receive, cred, so, so->so_label);
374
375         return (error);
376 }
377
378 static int
379 mac_socket_check_relabel(struct ucred *cred, struct socket *so,
380     struct label *newlabel)
381 {
382         int error;
383
384         SOCK_LOCK_ASSERT(so);
385
386         MAC_CHECK(socket_check_relabel, cred, so, so->so_label, newlabel);
387
388         return (error);
389 }
390
391 int
392 mac_socket_check_send(struct ucred *cred, struct socket *so)
393 {
394         int error;
395
396         SOCK_LOCK_ASSERT(so);
397
398         MAC_CHECK(socket_check_send, cred, so, so->so_label);
399
400         return (error);
401 }
402
403 int
404 mac_socket_check_stat(struct ucred *cred, struct socket *so)
405 {
406         int error;
407
408         SOCK_LOCK_ASSERT(so);
409
410         MAC_CHECK(socket_check_stat, cred, so, so->so_label);
411
412         return (error);
413 }
414
415 int
416 mac_socket_check_visible(struct ucred *cred, struct socket *so)
417 {
418         int error;
419
420         SOCK_LOCK_ASSERT(so);
421
422         MAC_CHECK(socket_check_visible, cred, so, so->so_label);
423
424         return (error);
425 }
426
427 int
428 mac_socket_label_set(struct ucred *cred, struct socket *so,
429     struct label *label)
430 {
431         int error;
432
433         /*
434          * We acquire the socket lock when we perform the test and set, but
435          * have to release it as the pcb code needs to acquire the pcb lock,
436          * which will precede the socket lock in the lock order.  However,
437          * this is fine, as any race will simply result in the inpcb being
438          * refreshed twice, but still consistently, as the inpcb code will
439          * acquire the socket lock before refreshing, holding both locks.
440          */
441         SOCK_LOCK(so);
442         error = mac_socket_check_relabel(cred, so, label);
443         if (error) {
444                 SOCK_UNLOCK(so);
445                 return (error);
446         }
447
448         mac_socket_relabel(cred, so, label);
449         SOCK_UNLOCK(so);
450
451         /*
452          * If the protocol has expressed interest in socket layer changes,
453          * such as if it needs to propagate changes to a cached pcb label
454          * from the socket, notify it of the label change while holding the
455          * socket lock.
456          */
457         if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
458                 (so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
459
460         return (0);
461 }
462
463 int
464 mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
465 {
466         struct label *intlabel;
467         char *buffer;
468         int error;
469
470         if (!(mac_labeled & MPC_OBJECT_SOCKET))
471                 return (EINVAL);
472
473         error = mac_check_structmac_consistent(mac);
474         if (error)
475                 return (error);
476
477         buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
478         error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
479         if (error) {
480                 free(buffer, M_MACTEMP);
481                 return (error);
482         }
483
484         intlabel = mac_socket_label_alloc(M_WAITOK);
485         error = mac_socket_internalize_label(intlabel, buffer);
486         free(buffer, M_MACTEMP);
487         if (error)
488                 goto out;
489
490         error = mac_socket_label_set(cred, so, intlabel);
491 out:
492         mac_socket_label_free(intlabel);
493         return (error);
494 }
495
496 int
497 mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
498 {
499         char *buffer, *elements;
500         struct label *intlabel;
501         int error;
502
503         if (!(mac_labeled & MPC_OBJECT_SOCKET))
504                 return (EINVAL);
505
506         error = mac_check_structmac_consistent(mac);
507         if (error)
508                 return (error);
509
510         elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
511         error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
512         if (error) {
513                 free(elements, M_MACTEMP);
514                 return (error);
515         }
516
517         buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
518         intlabel = mac_socket_label_alloc(M_WAITOK);
519         SOCK_LOCK(so);
520         mac_socket_copy_label(so->so_label, intlabel);
521         SOCK_UNLOCK(so);
522         error = mac_socket_externalize_label(intlabel, elements, buffer,
523             mac->m_buflen);
524         mac_socket_label_free(intlabel);
525         if (error == 0)
526                 error = copyout(buffer, mac->m_string, strlen(buffer)+1);
527
528         free(buffer, M_MACTEMP);
529         free(elements, M_MACTEMP);
530
531         return (error);
532 }
533
534 int
535 mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
536     struct mac *mac)
537 {
538         char *elements, *buffer;
539         struct label *intlabel;
540         int error;
541
542         if (!(mac_labeled & MPC_OBJECT_SOCKET))
543                 return (EINVAL);
544
545         error = mac_check_structmac_consistent(mac);
546         if (error)
547                 return (error);
548
549         elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
550         error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
551         if (error) {
552                 free(elements, M_MACTEMP);
553                 return (error);
554         }
555
556         buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
557         intlabel = mac_socket_label_alloc(M_WAITOK);
558         SOCK_LOCK(so);
559         mac_socket_copy_label(so->so_peerlabel, intlabel);
560         SOCK_UNLOCK(so);
561         error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
562             mac->m_buflen);
563         mac_socket_label_free(intlabel);
564         if (error == 0)
565                 error = copyout(buffer, mac->m_string, strlen(buffer)+1);
566
567         free(buffer, M_MACTEMP);
568         free(elements, M_MACTEMP);
569
570         return (error);
571 }