debuggers.hg

view xen/xsm/flask/ss/mls.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children b22f9ab1716a 001a99da1294
line source
1 /*
2 * Implementation of the multi-level security (MLS) policy.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
7 /*
8 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
9 *
10 * Support for enhanced MLS infrastructure.
11 *
12 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
13 */
15 /* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
17 #include <xen/lib.h>
18 #include <xen/xmalloc.h>
19 #include <xen/string.h>
20 #include <xen/errno.h>
21 #include "sidtab.h"
22 #include "mls.h"
23 #include "policydb.h"
24 #include "services.h"
26 /*
27 * Return the length in bytes for the MLS fields of the
28 * security context string representation of `context'.
29 */
30 int mls_compute_context_len(struct context * context)
31 {
32 int i, l, len, range;
33 struct ebitmap_node *node;
35 if (!flask_mls_enabled)
36 return 0;
38 len = 1; /* for the beginning ":" */
39 for ( l = 0; l < 2; l++ )
40 {
41 range = 0;
42 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
44 ebitmap_for_each_bit(&context->range.level[l].cat, node, i)
45 {
46 if ( ebitmap_node_get_bit(node, i) )
47 {
48 if ( range )
49 {
50 range++;
51 continue;
52 }
54 len += strlen(policydb.p_cat_val_to_name[i]) + 1;
55 range++;
56 }
57 else
58 {
59 if ( range > 1 )
60 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
61 range = 0;
62 }
63 }
64 /* Handle case where last category is the end of range */
65 if ( range > 1 )
66 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
68 if ( l == 0 )
69 {
70 if ( mls_level_eq(&context->range.level[0],
71 &context->range.level[1]) )
72 break;
73 else
74 len++;
75 }
76 }
78 return len;
79 }
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 context *context, char **scontext)
87 {
88 char *scontextp;
89 int i, l, range, wrote_sep;
90 struct ebitmap_node *node;
92 if ( !flask_mls_enabled )
93 return;
95 scontextp = *scontext;
97 *scontextp = ':';
98 scontextp++;
100 for ( l = 0; l < 2; l++ )
101 {
102 range = 0;
103 wrote_sep = 0;
104 strlcpy(scontextp,
105 policydb.p_sens_val_to_name[context->range.level[l].sens - 1],
106 strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]));
107 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
109 /* categories */
110 ebitmap_for_each_bit(&context->range.level[l].cat, node, i)
111 {
112 if ( ebitmap_node_get_bit(node, i) )
113 {
114 if ( range )
115 {
116 range++;
117 continue;
118 }
120 if ( !wrote_sep )
121 {
122 *scontextp++ = ':';
123 wrote_sep = 1;
124 }
125 else
126 *scontextp++ = ',';
127 strlcpy(scontextp, policydb.p_cat_val_to_name[i],
128 strlen(policydb.p_cat_val_to_name[i]));
129 scontextp += strlen(policydb.p_cat_val_to_name[i]);
130 range++;
131 }
132 else
133 {
134 if ( range > 1 )
135 {
136 if ( range > 2 )
137 *scontextp++ = '.';
138 else
139 *scontextp++ = ',';
141 strlcpy(scontextp, policydb.p_cat_val_to_name[i - 1],
142 strlen(policydb.p_cat_val_to_name[i - 1]));
143 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
144 }
145 range = 0;
146 }
147 }
149 /* Handle case where last category is the end of range */
150 if ( range > 1 )
151 {
152 if ( range > 2 )
153 *scontextp++ = '.';
154 else
155 *scontextp++ = ',';
157 strlcpy(scontextp, policydb.p_cat_val_to_name[i - 1],
158 strlen(policydb.p_cat_val_to_name[i - 1]));
159 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
160 }
162 if ( l == 0 )
163 {
164 if ( mls_level_eq(&context->range.level[0],
165 &context->range.level[1]) )
166 break;
167 else
168 {
169 *scontextp = '-';
170 scontextp++;
171 }
172 }
173 }
175 *scontext = scontextp;
176 return;
177 }
179 /*
180 * Return 1 if the MLS fields in the security context
181 * structure `c' are valid. Return 0 otherwise.
182 */
183 int mls_context_isvalid(struct policydb *p, struct context *c)
184 {
185 struct level_datum *levdatum;
186 struct user_datum *usrdatum;
187 struct ebitmap_node *node;
188 int i, l;
190 if ( !flask_mls_enabled )
191 return 1;
193 /*
194 * MLS range validity checks: high must dominate low, low level must
195 * be valid (category set <-> sensitivity check), and high level must
196 * be valid (category set <-> sensitivity check)
197 */
198 if ( !mls_level_dom(&c->range.level[1], &c->range.level[0]) )
199 /* High does not dominate low. */
200 return 0;
202 for ( l = 0; l < 2; l++ )
203 {
204 if ( !c->range.level[l].sens || c->range.level[l].sens >
205 p->p_levels.nprim )
206 return 0;
207 levdatum = hashtab_search(p->p_levels.table,
208 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
209 if ( !levdatum )
210 return 0;
212 ebitmap_for_each_bit(&c->range.level[l].cat, node, i)
213 {
214 if ( ebitmap_node_get_bit(node, i) )
215 {
216 if ( i > p->p_cats.nprim )
217 return 0;
218 if ( !ebitmap_get_bit(&levdatum->level->cat, i) )
219 /*
220 * Category may not be associated with
221 * sensitivity in low level.
222 */
223 return 0;
224 }
225 }
226 }
228 if ( c->role == OBJECT_R_VAL )
229 return 1;
231 /*
232 * User must be authorized for the MLS range.
233 */
234 if ( !c->user || c->user > p->p_users.nprim )
235 return 0;
236 usrdatum = p->user_val_to_struct[c->user - 1];
237 if ( !mls_range_contains(usrdatum->range, c->range) )
238 return 0; /* user may not be associated with range */
240 return 1;
241 }
243 /*
244 * Copies the MLS range from `src' into `dst'.
245 */
246 static inline int mls_copy_context(struct context *dst, struct context *src)
247 {
248 int l, rc = 0;
250 /* Copy the MLS range from the source context */
251 for ( l = 0; l < 2; l++ )
252 {
253 dst->range.level[l].sens = src->range.level[l].sens;
254 rc = ebitmap_cpy(&dst->range.level[l].cat,
255 &src->range.level[l].cat);
256 if ( rc )
257 break;
258 }
260 return rc;
261 }
263 /*
264 * Set the MLS fields in the security context structure
265 * `context' based on the string representation in
266 * the string `*scontext'. Update `*scontext' to
267 * point to the end of the string representation of
268 * the MLS fields.
269 *
270 * This function modifies the string in place, inserting
271 * NULL characters to terminate the MLS fields.
272 *
273 * If a def_sid is provided and no MLS field is present,
274 * copy the MLS field of the associated default context.
275 * Used for upgraded to MLS systems where objects may lack
276 * MLS fields.
277 *
278 * Policy read-lock must be held for sidtab lookup.
279 *
280 */
281 int mls_context_to_sid(char oldc, char **scontext, struct context *context,
282 struct sidtab *s, u32 def_sid)
283 {
285 char delim;
286 char *scontextp, *p, *rngptr;
287 struct level_datum *levdatum;
288 struct cat_datum *catdatum, *rngdatum;
289 int l, rc = -EINVAL;
291 if ( !flask_mls_enabled )
292 return 0;
294 /*
295 * No MLS component to the security context, try and map to
296 * default if provided.
297 */
298 if ( !oldc )
299 {
300 struct context *defcon;
302 if ( def_sid == SECSID_NULL )
303 goto out;
305 defcon = sidtab_search(s, def_sid);
306 if ( !defcon )
307 goto out;
309 rc = mls_copy_context(context, defcon);
310 goto out;
311 }
313 /* Extract low sensitivity. */
314 scontextp = p = *scontext;
315 while ( *p && *p != ':' && *p != '-' )
316 p++;
318 delim = *p;
319 if ( delim != 0 )
320 *p++ = 0;
322 for ( l = 0; l < 2; l++ )
323 {
324 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
325 if ( !levdatum )
326 {
327 rc = -EINVAL;
328 goto out;
329 }
331 context->range.level[l].sens = levdatum->level->sens;
333 if ( delim == ':' )
334 {
335 /* Extract category set. */
336 while ( 1 )
337 {
338 scontextp = p;
339 while ( *p && *p != ',' && *p != '-' )
340 p++;
341 delim = *p;
342 if ( delim != 0 )
343 *p++ = 0;
345 /* Separate into range if exists */
346 if ( (rngptr = strchr(scontextp, '.')) != NULL )
347 {
348 /* Remove '.' */
349 *rngptr++ = 0;
350 }
352 catdatum = hashtab_search(policydb.p_cats.table, scontextp);
353 if ( !catdatum )
354 {
355 rc = -EINVAL;
356 goto out;
357 }
359 rc = ebitmap_set_bit(&context->range.level[l].cat,
360 catdatum->value - 1, 1);
361 if ( rc )
362 goto out;
364 /* If range, set all categories in range */
365 if ( rngptr )
366 {
367 int i;
369 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
370 if ( !rngdatum )
371 {
372 rc = -EINVAL;
373 goto out;
374 }
376 if ( catdatum->value >= rngdatum->value )
377 {
378 rc = -EINVAL;
379 goto out;
380 }
382 for ( i = catdatum->value; i < rngdatum->value; i++ )
383 {
384 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
385 if ( rc )
386 goto out;
387 }
388 }
390 if ( delim != ',' )
391 break;
392 }
393 }
394 if ( delim == '-' )
395 {
396 /* Extract high sensitivity. */
397 scontextp = p;
398 while ( *p && *p != ':' )
399 p++;
401 delim = *p;
402 if ( delim != 0 )
403 *p++ = 0;
404 }
405 else
406 break;
407 }
409 if ( l == 0 )
410 {
411 context->range.level[1].sens = context->range.level[0].sens;
412 rc = ebitmap_cpy(&context->range.level[1].cat,
413 &context->range.level[0].cat);
414 if ( rc )
415 goto out;
416 }
417 *scontext = ++p;
418 rc = 0;
419 out:
420 return rc;
421 }
423 /*
424 * Copies the effective MLS range from `src' into `dst'.
425 */
426 static inline int mls_scopy_context(struct context *dst, struct context *src)
427 {
428 int l, rc = 0;
430 /* Copy the MLS range from the source context */
431 for ( l = 0; l < 2; l++ )
432 {
433 dst->range.level[l].sens = src->range.level[0].sens;
434 rc = ebitmap_cpy(&dst->range.level[l].cat,
435 &src->range.level[0].cat);
436 if ( rc )
437 break;
438 }
440 return rc;
441 }
443 /*
444 * Copies the MLS range `range' into `context'.
445 */
446 static inline int mls_range_set(struct context *context,
447 struct mls_range *range)
448 {
449 int l, rc = 0;
451 /* Copy the MLS range into the context */
452 for ( l = 0; l < 2; l++ )
453 {
454 context->range.level[l].sens = range->level[l].sens;
455 rc = ebitmap_cpy(&context->range.level[l].cat,
456 &range->level[l].cat);
457 if ( rc )
458 break;
459 }
461 return rc;
462 }
464 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
465 struct context *usercon)
466 {
467 if ( flask_mls_enabled )
468 {
469 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
470 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
471 struct mls_level *user_low = &(user->range.level[0]);
472 struct mls_level *user_clr = &(user->range.level[1]);
473 struct mls_level *user_def = &(user->dfltlevel);
474 struct mls_level *usercon_sen = &(usercon->range.level[0]);
475 struct mls_level *usercon_clr = &(usercon->range.level[1]);
477 /* Honor the user's default level if we can */
478 if ( mls_level_between(user_def, fromcon_sen, fromcon_clr) )
479 {
480 *usercon_sen = *user_def;
481 }
482 else if ( mls_level_between(fromcon_sen, user_def, user_clr) )
483 {
484 *usercon_sen = *fromcon_sen;
485 }
486 else if ( mls_level_between(fromcon_clr, user_low, user_def) )
487 {
488 *usercon_sen = *user_low;
489 }
490 else
491 return -EINVAL;
493 /* Lower the clearance of available contexts
494 if the clearance of "fromcon" is lower than
495 that of the user's default clearance (but
496 only if the "fromcon" clearance dominates
497 the user's computed sensitivity level) */
498 if ( mls_level_dom(user_clr, fromcon_clr) )
499 {
500 *usercon_clr = *fromcon_clr;
501 }
502 else if ( mls_level_dom(fromcon_clr, user_clr) )
503 {
504 *usercon_clr = *user_clr;
505 }
506 else
507 return -EINVAL;
508 }
510 return 0;
511 }
513 /*
514 * Convert the MLS fields in the security context
515 * structure `c' from the values specified in the
516 * policy `oldp' to the values specified in the policy `newp'.
517 */
518 int mls_convert_context(struct policydb *oldp, struct policydb *newp,
519 struct context *c)
520 {
521 struct level_datum *levdatum;
522 struct cat_datum *catdatum;
523 struct ebitmap bitmap;
524 struct ebitmap_node *node;
525 int l, i;
527 if ( !flask_mls_enabled )
528 return 0;
530 for ( l = 0; l < 2; l++ )
531 {
532 levdatum = hashtab_search(newp->p_levels.table,
533 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
535 if ( !levdatum )
536 return -EINVAL;
537 c->range.level[l].sens = levdatum->level->sens;
539 ebitmap_init(&bitmap);
540 ebitmap_for_each_bit(&c->range.level[l].cat, node, i)
541 {
542 if ( ebitmap_node_get_bit(node, i) )
543 {
544 int rc;
546 catdatum = hashtab_search(newp->p_cats.table,
547 oldp->p_cat_val_to_name[i]);
548 if ( !catdatum )
549 return -EINVAL;
550 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
551 if ( rc )
552 return rc;
553 }
554 }
555 ebitmap_destroy(&c->range.level[l].cat);
556 c->range.level[l].cat = bitmap;
557 }
559 return 0;
560 }
562 int mls_compute_sid(struct context *scontext, struct context *tcontext,
563 u16 tclass, u32 specified, struct context *newcontext)
564 {
565 if ( !flask_mls_enabled )
566 return 0;
568 switch ( specified )
569 {
570 case AVTAB_TRANSITION:
571 if ( tclass == SECCLASS_DOMAIN )
572 {
573 struct range_trans *rangetr;
574 /* Look for a range transition rule. */
575 for ( rangetr = policydb.range_tr; rangetr;
576 rangetr = rangetr->next)
577 {
578 if ( rangetr->dom == scontext->type &&
579 rangetr->type == tcontext->type)
580 {
581 /* Set the range from the rule */
582 return mls_range_set(newcontext, &rangetr->range);
583 }
584 }
585 }
586 /* Fallthrough */
587 case AVTAB_CHANGE:
588 if ( tclass == SECCLASS_DOMAIN )
589 /* Use the process MLS attributes. */
590 return mls_copy_context(newcontext, scontext);
591 else
592 /* Use the process effective MLS attributes. */
593 return mls_scopy_context(newcontext, scontext);
594 case AVTAB_MEMBER:
595 /* Only polyinstantiate the MLS attributes if
596 the type is being polyinstantiated */
597 if ( newcontext->type != tcontext->type )
598 {
599 /* Use the process effective MLS attributes. */
600 return mls_scopy_context(newcontext, scontext);
601 }
602 else
603 {
604 /* Use the related object MLS attributes. */
605 return mls_copy_context(newcontext, tcontext);
606 }
607 default:
608 return -EINVAL;
609 }
610 return -EINVAL;
611 }