Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/selinux/ss/mls.c
26436 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Implementation of the multi-level security (MLS) policy.
4
*
5
* Author : Stephen Smalley, <[email protected]>
6
*/
7
8
/*
9
* Updated: Trusted Computer Solutions, Inc. <[email protected]>
10
* Support for enhanced MLS infrastructure.
11
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12
*
13
* Updated: Hewlett-Packard <[email protected]>
14
* Added support to import/export the MLS label from NetLabel
15
* Copyright (C) Hewlett-Packard Development Company, L.P., 2006
16
*/
17
18
#include <linux/kernel.h>
19
#include <linux/slab.h>
20
#include <linux/string.h>
21
#include <linux/errno.h>
22
#include <net/netlabel.h>
23
#include "sidtab.h"
24
#include "mls.h"
25
#include "policydb.h"
26
#include "services.h"
27
28
/*
29
* Return the length in bytes for the MLS fields of the
30
* security context string representation of `context'.
31
*/
32
int mls_compute_context_len(struct policydb *p, struct context *context)
33
{
34
int i, l, len, head, prev;
35
char *nm;
36
struct ebitmap *e;
37
struct ebitmap_node *node;
38
39
if (!p->mls_enabled)
40
return 0;
41
42
len = 1; /* for the beginning ":" */
43
for (l = 0; l < 2; l++) {
44
u32 index_sens = context->range.level[l].sens;
45
len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1));
46
47
/* categories */
48
head = -2;
49
prev = -2;
50
e = &context->range.level[l].cat;
51
ebitmap_for_each_positive_bit(e, node, i)
52
{
53
if (i - prev > 1) {
54
/* one or more negative bits are skipped */
55
if (head != prev) {
56
nm = sym_name(p, SYM_CATS, prev);
57
len += strlen(nm) + 1;
58
}
59
nm = sym_name(p, SYM_CATS, i);
60
len += strlen(nm) + 1;
61
head = i;
62
}
63
prev = i;
64
}
65
if (prev != head) {
66
nm = sym_name(p, SYM_CATS, prev);
67
len += strlen(nm) + 1;
68
}
69
if (l == 0) {
70
if (mls_level_eq(&context->range.level[0],
71
&context->range.level[1]))
72
break;
73
else
74
len++;
75
}
76
}
77
78
return len;
79
}
80
81
/*
82
* Write the security context string representation of
83
* the MLS fields of `context' into the string `*scontext'.
84
* Update `*scontext' to point to the end of the MLS fields.
85
*/
86
void mls_sid_to_context(struct policydb *p, struct context *context,
87
char **scontext)
88
{
89
char *scontextp, *nm;
90
int i, l, head, prev;
91
struct ebitmap *e;
92
struct ebitmap_node *node;
93
94
if (!p->mls_enabled)
95
return;
96
97
scontextp = *scontext;
98
99
*scontextp = ':';
100
scontextp++;
101
102
for (l = 0; l < 2; l++) {
103
strcpy(scontextp, sym_name(p, SYM_LEVELS,
104
context->range.level[l].sens - 1));
105
scontextp += strlen(scontextp);
106
107
/* categories */
108
head = -2;
109
prev = -2;
110
e = &context->range.level[l].cat;
111
ebitmap_for_each_positive_bit(e, node, i)
112
{
113
if (i - prev > 1) {
114
/* one or more negative bits are skipped */
115
if (prev != head) {
116
if (prev - head > 1)
117
*scontextp++ = '.';
118
else
119
*scontextp++ = ',';
120
nm = sym_name(p, SYM_CATS, prev);
121
strcpy(scontextp, nm);
122
scontextp += strlen(nm);
123
}
124
if (prev < 0)
125
*scontextp++ = ':';
126
else
127
*scontextp++ = ',';
128
nm = sym_name(p, SYM_CATS, i);
129
strcpy(scontextp, nm);
130
scontextp += strlen(nm);
131
head = i;
132
}
133
prev = i;
134
}
135
136
if (prev != head) {
137
if (prev - head > 1)
138
*scontextp++ = '.';
139
else
140
*scontextp++ = ',';
141
nm = sym_name(p, SYM_CATS, prev);
142
strcpy(scontextp, nm);
143
scontextp += strlen(nm);
144
}
145
146
if (l == 0) {
147
if (mls_level_eq(&context->range.level[0],
148
&context->range.level[1]))
149
break;
150
else
151
*scontextp++ = '-';
152
}
153
}
154
155
*scontext = scontextp;
156
}
157
158
int mls_level_isvalid(struct policydb *p, struct mls_level *l)
159
{
160
struct level_datum *levdatum;
161
162
if (!l->sens || l->sens > p->p_levels.nprim)
163
return 0;
164
levdatum = symtab_search(&p->p_levels,
165
sym_name(p, SYM_LEVELS, l->sens - 1));
166
if (!levdatum)
167
return 0;
168
169
/*
170
* Return 1 iff all the bits set in l->cat are also be set in
171
* levdatum->level->cat and no bit in l->cat is larger than
172
* p->p_cats.nprim.
173
*/
174
return ebitmap_contains(&levdatum->level.cat, &l->cat,
175
p->p_cats.nprim);
176
}
177
178
int mls_range_isvalid(struct policydb *p, struct mls_range *r)
179
{
180
return (mls_level_isvalid(p, &r->level[0]) &&
181
mls_level_isvalid(p, &r->level[1]) &&
182
mls_level_dom(&r->level[1], &r->level[0]));
183
}
184
185
/*
186
* Return 1 if the MLS fields in the security context
187
* structure `c' are valid. Return 0 otherwise.
188
*/
189
int mls_context_isvalid(struct policydb *p, struct context *c)
190
{
191
struct user_datum *usrdatum;
192
193
if (!p->mls_enabled)
194
return 1;
195
196
if (!mls_range_isvalid(p, &c->range))
197
return 0;
198
199
if (c->role == OBJECT_R_VAL)
200
return 1;
201
202
/*
203
* User must be authorized for the MLS range.
204
*/
205
if (!c->user || c->user > p->p_users.nprim)
206
return 0;
207
usrdatum = p->user_val_to_struct[c->user - 1];
208
if (!mls_range_contains(usrdatum->range, c->range))
209
return 0; /* user may not be associated with range */
210
211
return 1;
212
}
213
214
/*
215
* Set the MLS fields in the security context structure
216
* `context' based on the string representation in
217
* the string `scontext'.
218
*
219
* This function modifies the string in place, inserting
220
* NULL characters to terminate the MLS fields.
221
*
222
* If a def_sid is provided and no MLS field is present,
223
* copy the MLS field of the associated default context.
224
* Used for upgraded to MLS systems where objects may lack
225
* MLS fields.
226
*
227
* Policy read-lock must be held for sidtab lookup.
228
*
229
*/
230
int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext,
231
struct context *context, struct sidtab *s, u32 def_sid)
232
{
233
char *sensitivity, *cur_cat, *next_cat, *rngptr;
234
struct level_datum *levdatum;
235
struct cat_datum *catdatum, *rngdatum;
236
u32 i;
237
int l, rc;
238
char *rangep[2];
239
240
if (!pol->mls_enabled) {
241
/*
242
* With no MLS, only return -EINVAL if there is a MLS field
243
* and it did not come from an xattr.
244
*/
245
if (oldc && def_sid == SECSID_NULL)
246
return -EINVAL;
247
return 0;
248
}
249
250
/*
251
* No MLS component to the security context, try and map to
252
* default if provided.
253
*/
254
if (!oldc) {
255
struct context *defcon;
256
257
if (def_sid == SECSID_NULL)
258
return -EINVAL;
259
260
defcon = sidtab_search(s, def_sid);
261
if (!defcon)
262
return -EINVAL;
263
264
return mls_context_cpy(context, defcon);
265
}
266
267
/*
268
* If we're dealing with a range, figure out where the two parts
269
* of the range begin.
270
*/
271
rangep[0] = scontext;
272
rangep[1] = strchr(scontext, '-');
273
if (rangep[1]) {
274
rangep[1][0] = '\0';
275
rangep[1]++;
276
}
277
278
/* For each part of the range: */
279
for (l = 0; l < 2; l++) {
280
/* Split sensitivity and category set. */
281
sensitivity = rangep[l];
282
if (sensitivity == NULL)
283
break;
284
next_cat = strchr(sensitivity, ':');
285
if (next_cat)
286
*(next_cat++) = '\0';
287
288
/* Parse sensitivity. */
289
levdatum = symtab_search(&pol->p_levels, sensitivity);
290
if (!levdatum)
291
return -EINVAL;
292
context->range.level[l].sens = levdatum->level.sens;
293
294
/* Extract category set. */
295
while (next_cat != NULL) {
296
cur_cat = next_cat;
297
next_cat = strchr(next_cat, ',');
298
if (next_cat != NULL)
299
*(next_cat++) = '\0';
300
301
/* Separate into range if exists */
302
rngptr = strchr(cur_cat, '.');
303
if (rngptr != NULL) {
304
/* Remove '.' */
305
*rngptr++ = '\0';
306
}
307
308
catdatum = symtab_search(&pol->p_cats, cur_cat);
309
if (!catdatum)
310
return -EINVAL;
311
312
rc = ebitmap_set_bit(&context->range.level[l].cat,
313
catdatum->value - 1, 1);
314
if (rc)
315
return rc;
316
317
/* If range, set all categories in range */
318
if (rngptr == NULL)
319
continue;
320
321
rngdatum = symtab_search(&pol->p_cats, rngptr);
322
if (!rngdatum)
323
return -EINVAL;
324
325
if (catdatum->value >= rngdatum->value)
326
return -EINVAL;
327
328
for (i = catdatum->value; i < rngdatum->value; i++) {
329
rc = ebitmap_set_bit(
330
&context->range.level[l].cat, i, 1);
331
if (rc)
332
return rc;
333
}
334
}
335
}
336
337
/* If we didn't see a '-', the range start is also the range end. */
338
if (rangep[1] == NULL) {
339
context->range.level[1].sens = context->range.level[0].sens;
340
rc = ebitmap_cpy(&context->range.level[1].cat,
341
&context->range.level[0].cat);
342
if (rc)
343
return rc;
344
}
345
346
return 0;
347
}
348
349
/*
350
* Set the MLS fields in the security context structure
351
* `context' based on the string representation in
352
* the string `str'. This function will allocate temporary memory with the
353
* given constraints of gfp_mask.
354
*/
355
int mls_from_string(struct policydb *p, char *str, struct context *context,
356
gfp_t gfp_mask)
357
{
358
char *tmpstr;
359
int rc;
360
361
if (!p->mls_enabled)
362
return -EINVAL;
363
364
tmpstr = kstrdup(str, gfp_mask);
365
if (!tmpstr) {
366
rc = -ENOMEM;
367
} else {
368
rc = mls_context_to_sid(p, ':', tmpstr, context, NULL,
369
SECSID_NULL);
370
kfree(tmpstr);
371
}
372
373
return rc;
374
}
375
376
/*
377
* Copies the MLS range `range' into `context'.
378
*/
379
int mls_range_set(struct context *context, struct mls_range *range)
380
{
381
int l, rc = 0;
382
383
/* Copy the MLS range into the context */
384
for (l = 0; l < 2; l++) {
385
context->range.level[l].sens = range->level[l].sens;
386
rc = ebitmap_cpy(&context->range.level[l].cat,
387
&range->level[l].cat);
388
if (rc)
389
break;
390
}
391
392
return rc;
393
}
394
395
int mls_setup_user_range(struct policydb *p, struct context *fromcon,
396
struct user_datum *user, struct context *usercon)
397
{
398
if (p->mls_enabled) {
399
struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
400
struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
401
struct mls_level *user_low = &(user->range.level[0]);
402
struct mls_level *user_clr = &(user->range.level[1]);
403
struct mls_level *user_def = &(user->dfltlevel);
404
struct mls_level *usercon_sen = &(usercon->range.level[0]);
405
struct mls_level *usercon_clr = &(usercon->range.level[1]);
406
407
/* Honor the user's default level if we can */
408
if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
409
*usercon_sen = *user_def;
410
else if (mls_level_between(fromcon_sen, user_def, user_clr))
411
*usercon_sen = *fromcon_sen;
412
else if (mls_level_between(fromcon_clr, user_low, user_def))
413
*usercon_sen = *user_low;
414
else
415
return -EINVAL;
416
417
/* Lower the clearance of available contexts
418
if the clearance of "fromcon" is lower than
419
that of the user's default clearance (but
420
only if the "fromcon" clearance dominates
421
the user's computed sensitivity level) */
422
if (mls_level_dom(user_clr, fromcon_clr))
423
*usercon_clr = *fromcon_clr;
424
else if (mls_level_dom(fromcon_clr, user_clr))
425
*usercon_clr = *user_clr;
426
else
427
return -EINVAL;
428
}
429
430
return 0;
431
}
432
433
/*
434
* Convert the MLS fields in the security context
435
* structure `oldc' from the values specified in the
436
* policy `oldp' to the values specified in the policy `newp',
437
* storing the resulting context in `newc'.
438
*/
439
int mls_convert_context(struct policydb *oldp, struct policydb *newp,
440
struct context *oldc, struct context *newc)
441
{
442
struct level_datum *levdatum;
443
struct cat_datum *catdatum;
444
struct ebitmap_node *node;
445
u32 i;
446
int l;
447
448
if (!oldp->mls_enabled || !newp->mls_enabled)
449
return 0;
450
451
for (l = 0; l < 2; l++) {
452
char *name = sym_name(oldp, SYM_LEVELS,
453
oldc->range.level[l].sens - 1);
454
455
levdatum = symtab_search(&newp->p_levels, name);
456
457
if (!levdatum)
458
return -EINVAL;
459
newc->range.level[l].sens = levdatum->level.sens;
460
461
ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node,
462
i)
463
{
464
int rc;
465
466
catdatum = symtab_search(&newp->p_cats,
467
sym_name(oldp, SYM_CATS, i));
468
if (!catdatum)
469
return -EINVAL;
470
rc = ebitmap_set_bit(&newc->range.level[l].cat,
471
catdatum->value - 1, 1);
472
if (rc)
473
return rc;
474
}
475
}
476
477
return 0;
478
}
479
480
int mls_compute_sid(struct policydb *p, struct context *scontext,
481
struct context *tcontext, u16 tclass, u32 specified,
482
struct context *newcontext, bool sock)
483
{
484
struct range_trans rtr;
485
struct mls_range *r;
486
struct class_datum *cladatum;
487
char default_range = 0;
488
489
if (!p->mls_enabled)
490
return 0;
491
492
switch (specified) {
493
case AVTAB_TRANSITION:
494
/* Look for a range transition rule. */
495
rtr.source_type = scontext->type;
496
rtr.target_type = tcontext->type;
497
rtr.target_class = tclass;
498
r = policydb_rangetr_search(p, &rtr);
499
if (r)
500
return mls_range_set(newcontext, r);
501
502
if (tclass && tclass <= p->p_classes.nprim) {
503
cladatum = p->class_val_to_struct[tclass - 1];
504
if (cladatum)
505
default_range = cladatum->default_range;
506
}
507
508
switch (default_range) {
509
case DEFAULT_SOURCE_LOW:
510
return mls_context_cpy_low(newcontext, scontext);
511
case DEFAULT_SOURCE_HIGH:
512
return mls_context_cpy_high(newcontext, scontext);
513
case DEFAULT_SOURCE_LOW_HIGH:
514
return mls_context_cpy(newcontext, scontext);
515
case DEFAULT_TARGET_LOW:
516
return mls_context_cpy_low(newcontext, tcontext);
517
case DEFAULT_TARGET_HIGH:
518
return mls_context_cpy_high(newcontext, tcontext);
519
case DEFAULT_TARGET_LOW_HIGH:
520
return mls_context_cpy(newcontext, tcontext);
521
case DEFAULT_GLBLUB:
522
return mls_context_glblub(newcontext, scontext,
523
tcontext);
524
}
525
526
fallthrough;
527
case AVTAB_CHANGE:
528
if ((tclass == p->process_class) || sock)
529
/* Use the process MLS attributes. */
530
return mls_context_cpy(newcontext, scontext);
531
else
532
/* Use the process effective MLS attributes. */
533
return mls_context_cpy_low(newcontext, scontext);
534
case AVTAB_MEMBER:
535
/* Use the process effective MLS attributes. */
536
return mls_context_cpy_low(newcontext, scontext);
537
}
538
return -EINVAL;
539
}
540
541
#ifdef CONFIG_NETLABEL
542
/**
543
* mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
544
* @p: the policy
545
* @context: the security context
546
* @secattr: the NetLabel security attributes
547
*
548
* Description:
549
* Given the security context copy the low MLS sensitivity level into the
550
* NetLabel MLS sensitivity level field.
551
*
552
*/
553
void mls_export_netlbl_lvl(struct policydb *p, struct context *context,
554
struct netlbl_lsm_secattr *secattr)
555
{
556
if (!p->mls_enabled)
557
return;
558
559
secattr->attr.mls.lvl = context->range.level[0].sens - 1;
560
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
561
}
562
563
/**
564
* mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
565
* @p: the policy
566
* @context: the security context
567
* @secattr: the NetLabel security attributes
568
*
569
* Description:
570
* Given the security context and the NetLabel security attributes, copy the
571
* NetLabel MLS sensitivity level into the context.
572
*
573
*/
574
void mls_import_netlbl_lvl(struct policydb *p, struct context *context,
575
struct netlbl_lsm_secattr *secattr)
576
{
577
if (!p->mls_enabled)
578
return;
579
580
context->range.level[0].sens = secattr->attr.mls.lvl + 1;
581
context->range.level[1].sens = context->range.level[0].sens;
582
}
583
584
/**
585
* mls_export_netlbl_cat - Export the MLS categories to NetLabel
586
* @p: the policy
587
* @context: the security context
588
* @secattr: the NetLabel security attributes
589
*
590
* Description:
591
* Given the security context copy the low MLS categories into the NetLabel
592
* MLS category field. Returns zero on success, negative values on failure.
593
*
594
*/
595
int mls_export_netlbl_cat(struct policydb *p, struct context *context,
596
struct netlbl_lsm_secattr *secattr)
597
{
598
int rc;
599
600
if (!p->mls_enabled)
601
return 0;
602
603
rc = ebitmap_netlbl_export(&context->range.level[0].cat,
604
&secattr->attr.mls.cat);
605
if (rc == 0 && secattr->attr.mls.cat != NULL)
606
secattr->flags |= NETLBL_SECATTR_MLS_CAT;
607
608
return rc;
609
}
610
611
/**
612
* mls_import_netlbl_cat - Import the MLS categories from NetLabel
613
* @p: the policy
614
* @context: the security context
615
* @secattr: the NetLabel security attributes
616
*
617
* Description:
618
* Copy the NetLabel security attributes into the SELinux context; since the
619
* NetLabel security attribute only contains a single MLS category use it for
620
* both the low and high categories of the context. Returns zero on success,
621
* negative values on failure.
622
*
623
*/
624
int mls_import_netlbl_cat(struct policydb *p, struct context *context,
625
struct netlbl_lsm_secattr *secattr)
626
{
627
int rc;
628
629
if (!p->mls_enabled)
630
return 0;
631
632
rc = ebitmap_netlbl_import(&context->range.level[0].cat,
633
secattr->attr.mls.cat);
634
if (rc)
635
goto import_netlbl_cat_failure;
636
memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
637
sizeof(context->range.level[0].cat));
638
639
return 0;
640
641
import_netlbl_cat_failure:
642
ebitmap_destroy(&context->range.level[0].cat);
643
return rc;
644
}
645
#endif /* CONFIG_NETLABEL */
646
647