Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/security/mac/mac_internal.h
39530 views
1
/*-
2
* Copyright (c) 1999-2002, 2006, 2009, 2019 Robert N. M. Watson
3
* Copyright (c) 2001 Ilmar S. Habibulin
4
* Copyright (c) 2001-2004 Networks Associates Technology, Inc.
5
* Copyright (c) 2006 nCircle Network Security, Inc.
6
* Copyright (c) 2006 SPARTA, Inc.
7
* Copyright (c) 2009 Apple, Inc.
8
* All rights reserved.
9
*
10
* This software was developed by Robert Watson and Ilmar Habibulin for the
11
* TrustedBSD Project.
12
*
13
* This software was developed for the FreeBSD Project in part by Network
14
* Associates Laboratories, the Security Research Division of Network
15
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
16
* as part of the DARPA CHATS research program.
17
*
18
* This software was developed by Robert N. M. Watson for the TrustedBSD
19
* Project under contract to nCircle Network Security, Inc.
20
*
21
* This software was enhanced by SPARTA ISSO under SPAWAR contract
22
* N66001-04-C-6019 ("SEFOS").
23
*
24
* This software was developed at the University of Cambridge Computer
25
* Laboratory with support from a grant from Google, Inc.
26
*
27
* Redistribution and use in source and binary forms, with or without
28
* modification, are permitted provided that the following conditions
29
* are met:
30
* 1. Redistributions of source code must retain the above copyright
31
* notice, this list of conditions and the following disclaimer.
32
* 2. Redistributions in binary form must reproduce the above copyright
33
* notice, this list of conditions and the following disclaimer in the
34
* documentation and/or other materials provided with the distribution.
35
*
36
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
37
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
40
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46
* SUCH DAMAGE.
47
*/
48
49
#ifndef _SECURITY_MAC_MAC_INTERNAL_H_
50
#define _SECURITY_MAC_MAC_INTERNAL_H_
51
52
#ifndef _KERNEL
53
#error "no user-serviceable parts inside"
54
#endif
55
56
#include <sys/lock.h>
57
#include <sys/rmlock.h>
58
59
/*
60
* MAC Framework SDT DTrace probe namespace, macros for declaring entry
61
* point probes, macros for invoking them.
62
*/
63
#ifdef SDT_PROVIDER_DECLARE
64
SDT_PROVIDER_DECLARE(mac); /* MAC Framework-level events. */
65
SDT_PROVIDER_DECLARE(mac_framework); /* Entry points to MAC. */
66
67
#define MAC_CHECK_PROBE_DEFINE4(name, arg0, arg1, arg2, arg3) \
68
SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__err, \
69
"int", arg0, arg1, arg2, arg3); \
70
SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__ok, \
71
"int", arg0, arg1, arg2, arg3);
72
73
#define MAC_CHECK_PROBE_DEFINE3(name, arg0, arg1, arg2) \
74
SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__err, \
75
"int", arg0, arg1, arg2); \
76
SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__ok, \
77
"int", arg0, arg1, arg2);
78
79
#define MAC_CHECK_PROBE_DEFINE2(name, arg0, arg1) \
80
SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__err, \
81
"int", arg0, arg1); \
82
SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__ok, \
83
"int", arg0, arg1);
84
85
#define MAC_CHECK_PROBE_DEFINE1(name, arg0) \
86
SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__err, \
87
"int", arg0); \
88
SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__ok, \
89
"int", arg0);
90
91
#define MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, arg3) do { \
92
if (SDT_PROBES_ENABLED()) { \
93
if (error) { \
94
SDT_PROBE5(mac_framework, , name, mac__check__err,\
95
error, arg0, arg1, arg2, arg3); \
96
} else { \
97
SDT_PROBE5(mac_framework, , name, mac__check__ok,\
98
0, arg0, arg1, arg2, arg3); \
99
} \
100
} \
101
} while (0)
102
103
#define MAC_CHECK_PROBE3(name, error, arg0, arg1, arg2) \
104
MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, 0)
105
#define MAC_CHECK_PROBE2(name, error, arg0, arg1) \
106
MAC_CHECK_PROBE3(name, error, arg0, arg1, 0)
107
#define MAC_CHECK_PROBE1(name, error, arg0) \
108
MAC_CHECK_PROBE2(name, error, arg0, 0)
109
#endif
110
111
#define MAC_GRANT_PROBE_DEFINE2(name, arg0, arg1) \
112
SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__err, \
113
"int", arg0, arg1); \
114
SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__ok, \
115
"int", arg0, arg1);
116
117
#define MAC_GRANT_PROBE2(name, error, arg0, arg1) do { \
118
if (SDT_PROBES_ENABLED()) { \
119
if (error) { \
120
SDT_PROBE3(mac_framework, , name, mac__grant__err,\
121
error, arg0, arg1); \
122
} else { \
123
SDT_PROBE3(mac_framework, , name, mac__grant__ok,\
124
error, arg0, arg1); \
125
} \
126
} \
127
} while (0)
128
129
/*
130
* MAC Framework global types and typedefs.
131
*/
132
LIST_HEAD(mac_policy_list_head, mac_policy_conf);
133
#ifdef MALLOC_DECLARE
134
MALLOC_DECLARE(M_MACTEMP);
135
#endif
136
137
/*
138
* MAC labels -- in-kernel storage format.
139
*
140
* In general, struct label pointers are embedded in kernel data structures
141
* representing objects that may be labeled (and protected). Struct label is
142
* opaque to both kernel services that invoke the MAC Framework and MAC
143
* policy modules. In particular, we do not wish to encode the layout of the
144
* label structure into any ABIs. Historically, the slot array contained
145
* unions of {long, void} but now contains uintptr_t.
146
*/
147
#define MAC_MAX_SLOTS 4
148
#define MAC_FLAG_INITIALIZED 0x0000001 /* Is initialized for use. */
149
struct label {
150
int l_flags;
151
intptr_t l_perpolicy[MAC_MAX_SLOTS];
152
};
153
154
/*
155
* Flags for mac_labeled, a bitmask of object types need across the union of
156
* all policies currently registered with the MAC Framework, used to key
157
* whether or not labels are allocated and constructors for the type are
158
* invoked.
159
*/
160
#define MPC_OBJECT_CRED 0x0000000000000001
161
#define MPC_OBJECT_PROC 0x0000000000000002
162
#define MPC_OBJECT_VNODE 0x0000000000000004
163
#define MPC_OBJECT_INPCB 0x0000000000000008
164
#define MPC_OBJECT_SOCKET 0x0000000000000010
165
#define MPC_OBJECT_DEVFS 0x0000000000000020
166
#define MPC_OBJECT_MBUF 0x0000000000000040
167
#define MPC_OBJECT_IPQ 0x0000000000000080
168
#define MPC_OBJECT_IFNET 0x0000000000000100
169
#define MPC_OBJECT_BPFDESC 0x0000000000000200
170
#define MPC_OBJECT_PIPE 0x0000000000000400
171
#define MPC_OBJECT_MOUNT 0x0000000000000800
172
#define MPC_OBJECT_POSIXSEM 0x0000000000001000
173
#define MPC_OBJECT_POSIXSHM 0x0000000000002000
174
#define MPC_OBJECT_SYSVMSG 0x0000000000004000
175
#define MPC_OBJECT_SYSVMSQ 0x0000000000008000
176
#define MPC_OBJECT_SYSVSEM 0x0000000000010000
177
#define MPC_OBJECT_SYSVSHM 0x0000000000020000
178
#define MPC_OBJECT_SYNCACHE 0x0000000000040000
179
#define MPC_OBJECT_IP6Q 0x0000000000080000
180
181
/*
182
* MAC Framework global variables.
183
*/
184
extern struct mac_policy_list_head mac_policy_list;
185
extern struct mac_policy_list_head mac_static_policy_list;
186
extern u_int mac_policy_count;
187
extern uint64_t mac_labeled;
188
extern struct mtx mac_ifnet_mtx;
189
190
/*
191
* MAC Framework infrastructure functions.
192
*/
193
int mac_error_select(int error1, int error2);
194
195
void mac_policy_slock_nosleep(struct rm_priotracker *tracker);
196
void mac_policy_slock_sleep(void);
197
void mac_policy_sunlock_nosleep(struct rm_priotracker *tracker);
198
void mac_policy_sunlock_sleep(void);
199
200
struct label *mac_labelzone_alloc(int flags);
201
void mac_labelzone_free(struct label *label);
202
void mac_labelzone_init(void);
203
204
void mac_init_label(struct label *label);
205
void mac_destroy_label(struct label *label);
206
int mac_check_structmac_consistent(const struct mac *mac);
207
int mac_allocate_slot(void);
208
209
/*
210
* Lock ifnets to protect labels only if ifnet labels are in use.
211
*/
212
#define MAC_IFNET_LOCK(ifp, locked) do { \
213
if (mac_labeled & MPC_OBJECT_IFNET) { \
214
mtx_lock(&mac_ifnet_mtx); \
215
locked = 1; \
216
} else { \
217
locked = 0; \
218
} \
219
} while (0)
220
221
#define MAC_IFNET_UNLOCK(ifp, locked) do { \
222
if (locked) { \
223
mtx_unlock(&mac_ifnet_mtx); \
224
locked = 0; \
225
} \
226
} while (0)
227
228
/*
229
* MAC Framework per-object type functions. It's not yet clear how the
230
* namespaces, etc, should work for these, so for now, sort by object type.
231
*/
232
struct label *mac_cred_label_alloc(void);
233
void mac_cred_label_free(struct label *label);
234
struct label *mac_pipe_label_alloc(void);
235
void mac_pipe_label_free(struct label *label);
236
struct label *mac_socket_label_alloc(int flag);
237
void mac_socket_label_free(struct label *label);
238
void mac_socketpeer_label_free(struct label *label);
239
struct label *mac_vnode_label_alloc(void);
240
void mac_vnode_label_free(struct label *label);
241
242
int mac_cred_check_relabel(struct ucred *cred, struct label *newlabel);
243
int mac_cred_externalize_label(struct label *label, char *elements,
244
char *outbuf, size_t outbuflen);
245
int mac_cred_internalize_label(struct label *label, char *string);
246
void mac_cred_relabel(struct ucred *cred, struct label *newlabel);
247
248
struct label *mac_mbuf_to_label(struct mbuf *m);
249
250
void mac_pipe_copy_label(struct label *src, struct label *dest);
251
int mac_pipe_externalize_label(struct label *label, char *elements,
252
char *outbuf, size_t outbuflen);
253
int mac_pipe_internalize_label(struct label *label, char *string);
254
255
int mac_socket_label_set(struct ucred *cred, struct socket *so,
256
struct label *label);
257
void mac_socket_copy_label(struct label *src, struct label *dest);
258
int mac_socket_externalize_label(struct label *label, char *elements,
259
char *outbuf, size_t outbuflen);
260
int mac_socket_internalize_label(struct label *label, char *string);
261
262
int mac_vnode_externalize_label(struct label *label, char *elements,
263
char *outbuf, size_t outbuflen);
264
int mac_vnode_internalize_label(struct label *label, char *string);
265
void mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
266
int *prot);
267
int vn_setlabel(struct vnode *vp, struct label *intlabel,
268
struct ucred *cred);
269
270
/*
271
* MAC Framework composition macros invoke all registered MAC policies for a
272
* specific entry point. They come in two forms: one which permits policies
273
* to sleep/block, and another that does not.
274
*
275
* MAC_POLICY_CHECK performs the designated check by walking the policy
276
* module list and checking with each as to how it feels about the request.
277
* Note that it returns its value via 'error' in the scope of the caller.
278
*/
279
#define MAC_POLICY_CHECK(check, args...) do { \
280
struct mac_policy_conf *mpc; \
281
\
282
error = 0; \
283
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
284
if (mpc->mpc_ops->mpo_ ## check != NULL) \
285
error = mac_error_select( \
286
mpc->mpc_ops->mpo_ ## check (args), \
287
error); \
288
} \
289
if (!LIST_EMPTY(&mac_policy_list)) { \
290
mac_policy_slock_sleep(); \
291
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
292
if (mpc->mpc_ops->mpo_ ## check != NULL) \
293
error = mac_error_select( \
294
mpc->mpc_ops->mpo_ ## check (args), \
295
error); \
296
} \
297
mac_policy_sunlock_sleep(); \
298
} \
299
} while (0)
300
301
#define MAC_POLICY_CHECK_NOSLEEP(check, args...) do { \
302
struct mac_policy_conf *mpc; \
303
\
304
error = 0; \
305
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
306
if (mpc->mpc_ops->mpo_ ## check != NULL) \
307
error = mac_error_select( \
308
mpc->mpc_ops->mpo_ ## check (args), \
309
error); \
310
} \
311
if (!LIST_EMPTY(&mac_policy_list)) { \
312
struct rm_priotracker tracker; \
313
\
314
mac_policy_slock_nosleep(&tracker); \
315
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
316
if (mpc->mpc_ops->mpo_ ## check != NULL) \
317
error = mac_error_select( \
318
mpc->mpc_ops->mpo_ ## check (args), \
319
error); \
320
} \
321
mac_policy_sunlock_nosleep(&tracker); \
322
} \
323
} while (0)
324
325
/*
326
* MAC_POLICY_GRANT performs the designated check by walking the policy
327
* module list and checking with each as to how it feels about the request.
328
* Unlike MAC_POLICY_CHECK, it grants if any policies return '0', and
329
* otherwise returns EPERM. Note that it returns its value via 'error' in
330
* the scope of the caller.
331
*/
332
#define MAC_POLICY_GRANT_NOSLEEP(check, args...) do { \
333
struct mac_policy_conf *mpc; \
334
\
335
error = EPERM; \
336
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
337
if (mpc->mpc_ops->mpo_ ## check != NULL) { \
338
if (mpc->mpc_ops->mpo_ ## check(args) == 0) \
339
error = 0; \
340
} \
341
} \
342
if (!LIST_EMPTY(&mac_policy_list)) { \
343
struct rm_priotracker tracker; \
344
\
345
mac_policy_slock_nosleep(&tracker); \
346
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
347
if (mpc->mpc_ops->mpo_ ## check != NULL) { \
348
if (mpc->mpc_ops->mpo_ ## check (args) \
349
== 0) \
350
error = 0; \
351
} \
352
} \
353
mac_policy_sunlock_nosleep(&tracker); \
354
} \
355
} while (0)
356
357
/*
358
* MAC_POLICY_BOOLEAN performs the designated boolean composition by walking
359
* the module list, invoking each instance of the operation, and combining
360
* the results using the passed C operator. Note that it returns its value
361
* via 'result' in the scope of the caller, which should be initialized by
362
* the caller in a meaningful way to get a meaningful result.
363
*/
364
#define MAC_POLICY_BOOLEAN(operation, composition, args...) do { \
365
struct mac_policy_conf *mpc; \
366
\
367
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
368
if (mpc->mpc_ops->mpo_ ## operation != NULL) \
369
result = result composition \
370
mpc->mpc_ops->mpo_ ## operation (args); \
371
} \
372
if (!LIST_EMPTY(&mac_policy_list)) { \
373
mac_policy_slock_sleep(); \
374
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
375
if (mpc->mpc_ops->mpo_ ## operation != NULL) \
376
result = result composition \
377
mpc->mpc_ops->mpo_ ## operation \
378
(args); \
379
} \
380
mac_policy_sunlock_sleep(); \
381
} \
382
} while (0)
383
384
#define MAC_POLICY_BOOLEAN_NOSLEEP(operation, composition, args...) do {\
385
struct mac_policy_conf *mpc; \
386
\
387
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
388
if (mpc->mpc_ops->mpo_ ## operation != NULL) \
389
result = result composition \
390
mpc->mpc_ops->mpo_ ## operation (args); \
391
} \
392
if (!LIST_EMPTY(&mac_policy_list)) { \
393
struct rm_priotracker tracker; \
394
\
395
mac_policy_slock_nosleep(&tracker); \
396
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
397
if (mpc->mpc_ops->mpo_ ## operation != NULL) \
398
result = result composition \
399
mpc->mpc_ops->mpo_ ## operation \
400
(args); \
401
} \
402
mac_policy_sunlock_nosleep(&tracker); \
403
} \
404
} while (0)
405
406
/*
407
* MAC_POLICY_EXTERNALIZE queries each policy to see if it can generate an
408
* externalized version of a label element by name. Policies declare whether
409
* they have matched a particular element name, parsed from the string by
410
* MAC_POLICY_EXTERNALIZE, and an error is returned if any element is matched
411
* by no policy.
412
*/
413
#define MAC_POLICY_EXTERNALIZE(type, label, elementlist, outbuf, \
414
outbuflen) do { \
415
int claimed, first, ignorenotfound, savedlen; \
416
char *element_name, *element_temp; \
417
struct sbuf sb; \
418
\
419
error = 0; \
420
first = 1; \
421
sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN); \
422
element_temp = elementlist; \
423
while ((element_name = strsep(&element_temp, ",")) != NULL) { \
424
if (element_name[0] == '?') { \
425
element_name++; \
426
ignorenotfound = 1; \
427
} else \
428
ignorenotfound = 0; \
429
savedlen = sbuf_len(&sb); \
430
if (first) \
431
error = sbuf_printf(&sb, "%s/", element_name); \
432
else \
433
error = sbuf_printf(&sb, ",%s/", element_name); \
434
if (error == -1) { \
435
error = EINVAL; /* XXX: E2BIG? */ \
436
break; \
437
} \
438
claimed = 0; \
439
MAC_POLICY_CHECK(type ## _externalize_label, label, \
440
element_name, &sb, &claimed); \
441
if (error) \
442
break; \
443
if (claimed == 0 && ignorenotfound) { \
444
/* Revert last label name. */ \
445
sbuf_setpos(&sb, savedlen); \
446
} else if (claimed != 1) { \
447
error = EINVAL; /* XXX: ENOLABEL? */ \
448
break; \
449
} else { \
450
first = 0; \
451
} \
452
} \
453
sbuf_finish(&sb); \
454
} while (0)
455
456
/*
457
* MAC_POLICY_INTERNALIZE presents parsed element names and data to each
458
* policy to see if any is willing to claim it and internalize the label
459
* data. If no policies match, an error is returned.
460
*/
461
#define MAC_POLICY_INTERNALIZE(type, label, instring) do { \
462
char *element, *element_name, *element_data; \
463
int claimed; \
464
\
465
error = 0; \
466
element = instring; \
467
while ((element_name = strsep(&element, ",")) != NULL) { \
468
element_data = element_name; \
469
element_name = strsep(&element_data, "/"); \
470
if (element_data == NULL) { \
471
error = EINVAL; \
472
break; \
473
} \
474
claimed = 0; \
475
MAC_POLICY_CHECK(type ## _internalize_label, label, \
476
element_name, element_data, &claimed); \
477
if (error) \
478
break; \
479
if (claimed != 1) { \
480
/* XXXMAC: Another error here? */ \
481
error = EINVAL; \
482
break; \
483
} \
484
} \
485
} while (0)
486
487
/*
488
* MAC_POLICY_PERFORM performs the designated operation by walking the policy
489
* module list and invoking that operation for each policy.
490
*/
491
#define MAC_POLICY_PERFORM(operation, args...) do { \
492
struct mac_policy_conf *mpc; \
493
\
494
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
495
if (mpc->mpc_ops->mpo_ ## operation != NULL) \
496
mpc->mpc_ops->mpo_ ## operation (args); \
497
} \
498
if (!LIST_EMPTY(&mac_policy_list)) { \
499
mac_policy_slock_sleep(); \
500
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
501
if (mpc->mpc_ops->mpo_ ## operation != NULL) \
502
mpc->mpc_ops->mpo_ ## operation (args); \
503
} \
504
mac_policy_sunlock_sleep(); \
505
} \
506
} while (0)
507
508
#define MAC_POLICY_PERFORM_NOSLEEP(operation, args...) do { \
509
struct mac_policy_conf *mpc; \
510
\
511
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
512
if (mpc->mpc_ops->mpo_ ## operation != NULL) \
513
mpc->mpc_ops->mpo_ ## operation (args); \
514
} \
515
if (!LIST_EMPTY(&mac_policy_list)) { \
516
struct rm_priotracker tracker; \
517
\
518
mac_policy_slock_nosleep(&tracker); \
519
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
520
if (mpc->mpc_ops->mpo_ ## operation != NULL) \
521
mpc->mpc_ops->mpo_ ## operation (args); \
522
} \
523
mac_policy_sunlock_nosleep(&tracker); \
524
} \
525
} while (0)
526
527
#endif /* !_SECURITY_MAC_MAC_INTERNAL_H_ */
528
529