[MLSXFRM]: Define new SELinux service routine
[deliverable/linux.git] / security / selinux / ss / mls.c
CommitLineData
1da177e4
LT
1/*
2 * Implementation of the multi-level security (MLS) policy.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6/*
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 *
9 * Support for enhanced MLS infrastructure.
10 *
376bd9cb 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
1da177e4
LT
12 */
13
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/string.h>
17#include <linux/errno.h>
f5c1d5b2 18#include "sidtab.h"
1da177e4
LT
19#include "mls.h"
20#include "policydb.h"
21#include "services.h"
22
23/*
24 * Return the length in bytes for the MLS fields of the
25 * security context string representation of `context'.
26 */
27int mls_compute_context_len(struct context * context)
28{
29 int i, l, len, range;
782ebb99 30 struct ebitmap_node *node;
1da177e4
LT
31
32 if (!selinux_mls_enabled)
33 return 0;
34
35 len = 1; /* for the beginning ":" */
36 for (l = 0; l < 2; l++) {
37 range = 0;
38 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
39
782ebb99
SS
40 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
41 if (ebitmap_node_get_bit(node, i)) {
1da177e4
LT
42 if (range) {
43 range++;
44 continue;
45 }
46
782ebb99 47 len += strlen(policydb.p_cat_val_to_name[i]) + 1;
1da177e4
LT
48 range++;
49 } else {
50 if (range > 1)
782ebb99 51 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
1da177e4
LT
52 range = 0;
53 }
54 }
55 /* Handle case where last category is the end of range */
56 if (range > 1)
782ebb99 57 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
1da177e4
LT
58
59 if (l == 0) {
60 if (mls_level_eq(&context->range.level[0],
61 &context->range.level[1]))
62 break;
63 else
64 len++;
65 }
66 }
67
68 return len;
69}
70
71/*
72 * Write the security context string representation of
73 * the MLS fields of `context' into the string `*scontext'.
74 * Update `*scontext' to point to the end of the MLS fields.
75 */
76void mls_sid_to_context(struct context *context,
77 char **scontext)
78{
79 char *scontextp;
80 int i, l, range, wrote_sep;
782ebb99 81 struct ebitmap_node *node;
1da177e4
LT
82
83 if (!selinux_mls_enabled)
84 return;
85
86 scontextp = *scontext;
87
88 *scontextp = ':';
89 scontextp++;
90
91 for (l = 0; l < 2; l++) {
92 range = 0;
93 wrote_sep = 0;
94 strcpy(scontextp,
95 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
96 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
97
98 /* categories */
782ebb99
SS
99 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
100 if (ebitmap_node_get_bit(node, i)) {
1da177e4
LT
101 if (range) {
102 range++;
103 continue;
104 }
105
106 if (!wrote_sep) {
107 *scontextp++ = ':';
108 wrote_sep = 1;
109 } else
110 *scontextp++ = ',';
782ebb99
SS
111 strcpy(scontextp, policydb.p_cat_val_to_name[i]);
112 scontextp += strlen(policydb.p_cat_val_to_name[i]);
1da177e4
LT
113 range++;
114 } else {
115 if (range > 1) {
116 if (range > 2)
117 *scontextp++ = '.';
118 else
119 *scontextp++ = ',';
120
782ebb99
SS
121 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
122 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
1da177e4
LT
123 }
124 range = 0;
125 }
126 }
127
128 /* Handle case where last category is the end of range */
129 if (range > 1) {
130 if (range > 2)
131 *scontextp++ = '.';
132 else
133 *scontextp++ = ',';
134
782ebb99
SS
135 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
136 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
1da177e4
LT
137 }
138
139 if (l == 0) {
140 if (mls_level_eq(&context->range.level[0],
141 &context->range.level[1]))
142 break;
143 else {
144 *scontextp = '-';
145 scontextp++;
146 }
147 }
148 }
149
150 *scontext = scontextp;
151 return;
152}
153
154/*
155 * Return 1 if the MLS fields in the security context
156 * structure `c' are valid. Return 0 otherwise.
157 */
158int mls_context_isvalid(struct policydb *p, struct context *c)
159{
160 struct level_datum *levdatum;
161 struct user_datum *usrdatum;
782ebb99 162 struct ebitmap_node *node;
1da177e4
LT
163 int i, l;
164
165 if (!selinux_mls_enabled)
166 return 1;
167
168 /*
169 * MLS range validity checks: high must dominate low, low level must
170 * be valid (category set <-> sensitivity check), and high level must
171 * be valid (category set <-> sensitivity check)
172 */
173 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
174 /* High does not dominate low. */
175 return 0;
176
177 for (l = 0; l < 2; l++) {
178 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
179 return 0;
180 levdatum = hashtab_search(p->p_levels.table,
181 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
182 if (!levdatum)
183 return 0;
184
782ebb99
SS
185 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
186 if (ebitmap_node_get_bit(node, i)) {
1da177e4
LT
187 if (i > p->p_cats.nprim)
188 return 0;
782ebb99 189 if (!ebitmap_get_bit(&levdatum->level->cat, i))
1da177e4
LT
190 /*
191 * Category may not be associated with
192 * sensitivity in low level.
193 */
194 return 0;
195 }
196 }
197 }
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'. Update `*scontext' to
218 * point to the end of the string representation of
219 * the MLS fields.
220 *
221 * This function modifies the string in place, inserting
222 * NULL characters to terminate the MLS fields.
f5c1d5b2
JM
223 *
224 * If a def_sid is provided and no MLS field is present,
225 * copy the MLS field of the associated default context.
226 * Used for upgraded to MLS systems where objects may lack
227 * MLS fields.
228 *
229 * Policy read-lock must be held for sidtab lookup.
230 *
1da177e4
LT
231 */
232int mls_context_to_sid(char oldc,
233 char **scontext,
f5c1d5b2
JM
234 struct context *context,
235 struct sidtab *s,
236 u32 def_sid)
1da177e4
LT
237{
238
239 char delim;
240 char *scontextp, *p, *rngptr;
241 struct level_datum *levdatum;
242 struct cat_datum *catdatum, *rngdatum;
243 int l, rc = -EINVAL;
244
e517a0cd
SS
245 if (!selinux_mls_enabled) {
246 if (def_sid != SECSID_NULL && oldc)
ab5703b3 247 *scontext += strlen(*scontext)+1;
1da177e4 248 return 0;
e517a0cd 249 }
1da177e4 250
f5c1d5b2
JM
251 /*
252 * No MLS component to the security context, try and map to
253 * default if provided.
254 */
255 if (!oldc) {
256 struct context *defcon;
257
258 if (def_sid == SECSID_NULL)
259 goto out;
260
261 defcon = sidtab_search(s, def_sid);
262 if (!defcon)
263 goto out;
264
265 rc = mls_copy_context(context, defcon);
1da177e4 266 goto out;
f5c1d5b2 267 }
1da177e4
LT
268
269 /* Extract low sensitivity. */
270 scontextp = p = *scontext;
271 while (*p && *p != ':' && *p != '-')
272 p++;
273
274 delim = *p;
275 if (delim != 0)
276 *p++ = 0;
277
278 for (l = 0; l < 2; l++) {
279 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
280 if (!levdatum) {
281 rc = -EINVAL;
282 goto out;
283 }
284
285 context->range.level[l].sens = levdatum->level->sens;
286
287 if (delim == ':') {
288 /* Extract category set. */
289 while (1) {
290 scontextp = p;
291 while (*p && *p != ',' && *p != '-')
292 p++;
293 delim = *p;
294 if (delim != 0)
295 *p++ = 0;
296
297 /* Separate into range if exists */
298 if ((rngptr = strchr(scontextp, '.')) != NULL) {
299 /* Remove '.' */
300 *rngptr++ = 0;
301 }
302
303 catdatum = hashtab_search(policydb.p_cats.table,
304 scontextp);
305 if (!catdatum) {
306 rc = -EINVAL;
307 goto out;
308 }
309
310 rc = ebitmap_set_bit(&context->range.level[l].cat,
311 catdatum->value - 1, 1);
312 if (rc)
313 goto out;
314
315 /* If range, set all categories in range */
316 if (rngptr) {
317 int i;
318
319 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
320 if (!rngdatum) {
321 rc = -EINVAL;
322 goto out;
323 }
324
325 if (catdatum->value >= rngdatum->value) {
326 rc = -EINVAL;
327 goto out;
328 }
329
330 for (i = catdatum->value; i < rngdatum->value; i++) {
331 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
332 if (rc)
333 goto out;
334 }
335 }
336
337 if (delim != ',')
338 break;
339 }
340 }
341 if (delim == '-') {
342 /* Extract high sensitivity. */
343 scontextp = p;
344 while (*p && *p != ':')
345 p++;
346
347 delim = *p;
348 if (delim != 0)
349 *p++ = 0;
350 } else
351 break;
352 }
353
354 if (l == 0) {
355 context->range.level[1].sens = context->range.level[0].sens;
356 rc = ebitmap_cpy(&context->range.level[1].cat,
357 &context->range.level[0].cat);
358 if (rc)
359 goto out;
360 }
361 *scontext = ++p;
362 rc = 0;
363out:
364 return rc;
365}
366
376bd9cb
DG
367/*
368 * Set the MLS fields in the security context structure
369 * `context' based on the string representation in
370 * the string `str'. This function will allocate temporary memory with the
371 * given constraints of gfp_mask.
372 */
373int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
374{
375 char *tmpstr, *freestr;
376 int rc;
377
378 if (!selinux_mls_enabled)
379 return -EINVAL;
380
381 /* we need freestr because mls_context_to_sid will change
382 the value of tmpstr */
383 tmpstr = freestr = kstrdup(str, gfp_mask);
384 if (!tmpstr) {
385 rc = -ENOMEM;
386 } else {
387 rc = mls_context_to_sid(':', &tmpstr, context,
388 NULL, SECSID_NULL);
389 kfree(freestr);
390 }
391
392 return rc;
393}
394
1da177e4
LT
395/*
396 * Copies the effective MLS range from `src' into `dst'.
397 */
398static inline int mls_scopy_context(struct context *dst,
399 struct context *src)
400{
401 int l, rc = 0;
402
403 /* Copy the MLS range from the source context */
404 for (l = 0; l < 2; l++) {
405 dst->range.level[l].sens = src->range.level[0].sens;
406 rc = ebitmap_cpy(&dst->range.level[l].cat,
407 &src->range.level[0].cat);
408 if (rc)
409 break;
410 }
411
412 return rc;
413}
414
415/*
416 * Copies the MLS range `range' into `context'.
417 */
418static inline int mls_range_set(struct context *context,
419 struct mls_range *range)
420{
421 int l, rc = 0;
422
423 /* Copy the MLS range into the context */
424 for (l = 0; l < 2; l++) {
425 context->range.level[l].sens = range->level[l].sens;
426 rc = ebitmap_cpy(&context->range.level[l].cat,
427 &range->level[l].cat);
428 if (rc)
429 break;
430 }
431
432 return rc;
433}
434
435int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
436 struct context *usercon)
437{
438 if (selinux_mls_enabled) {
439 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
440 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
441 struct mls_level *user_low = &(user->range.level[0]);
442 struct mls_level *user_clr = &(user->range.level[1]);
443 struct mls_level *user_def = &(user->dfltlevel);
444 struct mls_level *usercon_sen = &(usercon->range.level[0]);
445 struct mls_level *usercon_clr = &(usercon->range.level[1]);
446
447 /* Honor the user's default level if we can */
448 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
449 *usercon_sen = *user_def;
450 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
451 *usercon_sen = *fromcon_sen;
452 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
453 *usercon_sen = *user_low;
454 } else
455 return -EINVAL;
456
457 /* Lower the clearance of available contexts
458 if the clearance of "fromcon" is lower than
459 that of the user's default clearance (but
460 only if the "fromcon" clearance dominates
461 the user's computed sensitivity level) */
462 if (mls_level_dom(user_clr, fromcon_clr)) {
463 *usercon_clr = *fromcon_clr;
464 } else if (mls_level_dom(fromcon_clr, user_clr)) {
465 *usercon_clr = *user_clr;
466 } else
467 return -EINVAL;
468 }
469
470 return 0;
471}
472
473/*
474 * Convert the MLS fields in the security context
475 * structure `c' from the values specified in the
476 * policy `oldp' to the values specified in the policy `newp'.
477 */
478int mls_convert_context(struct policydb *oldp,
479 struct policydb *newp,
480 struct context *c)
481{
482 struct level_datum *levdatum;
483 struct cat_datum *catdatum;
484 struct ebitmap bitmap;
782ebb99 485 struct ebitmap_node *node;
1da177e4
LT
486 int l, i;
487
488 if (!selinux_mls_enabled)
489 return 0;
490
491 for (l = 0; l < 2; l++) {
492 levdatum = hashtab_search(newp->p_levels.table,
493 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
494
495 if (!levdatum)
496 return -EINVAL;
497 c->range.level[l].sens = levdatum->level->sens;
498
499 ebitmap_init(&bitmap);
782ebb99
SS
500 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
501 if (ebitmap_node_get_bit(node, i)) {
1da177e4
LT
502 int rc;
503
504 catdatum = hashtab_search(newp->p_cats.table,
782ebb99 505 oldp->p_cat_val_to_name[i]);
1da177e4
LT
506 if (!catdatum)
507 return -EINVAL;
508 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
509 if (rc)
510 return rc;
511 }
512 }
513 ebitmap_destroy(&c->range.level[l].cat);
514 c->range.level[l].cat = bitmap;
515 }
516
517 return 0;
518}
519
520int mls_compute_sid(struct context *scontext,
521 struct context *tcontext,
522 u16 tclass,
523 u32 specified,
524 struct context *newcontext)
525{
526 if (!selinux_mls_enabled)
527 return 0;
528
529 switch (specified) {
530 case AVTAB_TRANSITION:
531 if (tclass == SECCLASS_PROCESS) {
532 struct range_trans *rangetr;
533 /* Look for a range transition rule. */
534 for (rangetr = policydb.range_tr; rangetr;
535 rangetr = rangetr->next) {
536 if (rangetr->dom == scontext->type &&
537 rangetr->type == tcontext->type) {
538 /* Set the range from the rule */
539 return mls_range_set(newcontext,
540 &rangetr->range);
541 }
542 }
543 }
544 /* Fallthrough */
545 case AVTAB_CHANGE:
546 if (tclass == SECCLASS_PROCESS)
547 /* Use the process MLS attributes. */
548 return mls_copy_context(newcontext, scontext);
549 else
550 /* Use the process effective MLS attributes. */
551 return mls_scopy_context(newcontext, scontext);
552 case AVTAB_MEMBER:
553 /* Only polyinstantiate the MLS attributes if
554 the type is being polyinstantiated */
555 if (newcontext->type != tcontext->type) {
556 /* Use the process effective MLS attributes. */
557 return mls_scopy_context(newcontext, scontext);
558 } else {
559 /* Use the related object MLS attributes. */
560 return mls_copy_context(newcontext, tcontext);
561 }
562 default:
563 return -EINVAL;
564 }
565 return -EINVAL;
566}
567
This page took 0.163093 seconds and 5 git commands to generate.