]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/security/mac/mac_socket.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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 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 }