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