[PATCH] USB: ftdi_sio: new microHAM and Evolution Robotics devices
[linux-2.6/zen-sources.git] / security / selinux / ss / mls.c
blobd4c32c39ccc9db9533eb1fb60f495edeb94fe77d
1 /*
2 * Implementation of the multi-level security (MLS) policy.
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6 /*
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
9 * Support for enhanced MLS infrastructure.
11 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
16 #include <linux/string.h>
17 #include <linux/errno.h>
18 #include "sidtab.h"
19 #include "mls.h"
20 #include "policydb.h"
21 #include "services.h"
24 * Return the length in bytes for the MLS fields of the
25 * security context string representation of `context'.
27 int mls_compute_context_len(struct context * context)
29 int i, l, len, range;
31 if (!selinux_mls_enabled)
32 return 0;
34 len = 1; /* for the beginning ":" */
35 for (l = 0; l < 2; l++) {
36 range = 0;
37 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
39 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
40 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
41 if (range) {
42 range++;
43 continue;
46 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
47 range++;
48 } else {
49 if (range > 1)
50 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
51 range = 0;
54 /* Handle case where last category is the end of range */
55 if (range > 1)
56 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
58 if (l == 0) {
59 if (mls_level_eq(&context->range.level[0],
60 &context->range.level[1]))
61 break;
62 else
63 len++;
67 return len;
71 * Write the security context string representation of
72 * the MLS fields of `context' into the string `*scontext'.
73 * Update `*scontext' to point to the end of the MLS fields.
75 void mls_sid_to_context(struct context *context,
76 char **scontext)
78 char *scontextp;
79 int i, l, range, wrote_sep;
81 if (!selinux_mls_enabled)
82 return;
84 scontextp = *scontext;
86 *scontextp = ':';
87 scontextp++;
89 for (l = 0; l < 2; l++) {
90 range = 0;
91 wrote_sep = 0;
92 strcpy(scontextp,
93 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
94 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
96 /* categories */
97 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
98 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
99 if (range) {
100 range++;
101 continue;
104 if (!wrote_sep) {
105 *scontextp++ = ':';
106 wrote_sep = 1;
107 } else
108 *scontextp++ = ',';
109 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
110 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
111 range++;
112 } else {
113 if (range > 1) {
114 if (range > 2)
115 *scontextp++ = '.';
116 else
117 *scontextp++ = ',';
119 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
120 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
122 range = 0;
126 /* Handle case where last category is the end of range */
127 if (range > 1) {
128 if (range > 2)
129 *scontextp++ = '.';
130 else
131 *scontextp++ = ',';
133 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
134 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
137 if (l == 0) {
138 if (mls_level_eq(&context->range.level[0],
139 &context->range.level[1]))
140 break;
141 else {
142 *scontextp = '-';
143 scontextp++;
148 *scontext = scontextp;
149 return;
153 * Return 1 if the MLS fields in the security context
154 * structure `c' are valid. Return 0 otherwise.
156 int mls_context_isvalid(struct policydb *p, struct context *c)
158 struct level_datum *levdatum;
159 struct user_datum *usrdatum;
160 int i, l;
162 if (!selinux_mls_enabled)
163 return 1;
166 * MLS range validity checks: high must dominate low, low level must
167 * be valid (category set <-> sensitivity check), and high level must
168 * be valid (category set <-> sensitivity check)
170 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
171 /* High does not dominate low. */
172 return 0;
174 for (l = 0; l < 2; l++) {
175 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
176 return 0;
177 levdatum = hashtab_search(p->p_levels.table,
178 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
179 if (!levdatum)
180 return 0;
182 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
183 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
184 if (i > p->p_cats.nprim)
185 return 0;
186 if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
188 * Category may not be associated with
189 * sensitivity in low level.
191 return 0;
196 if (c->role == OBJECT_R_VAL)
197 return 1;
200 * User must be authorized for the MLS range.
202 if (!c->user || c->user > p->p_users.nprim)
203 return 0;
204 usrdatum = p->user_val_to_struct[c->user - 1];
205 if (!mls_range_contains(usrdatum->range, c->range))
206 return 0; /* user may not be associated with range */
208 return 1;
212 * Copies the MLS range from `src' into `dst'.
214 static inline int mls_copy_context(struct context *dst,
215 struct context *src)
217 int l, rc = 0;
219 /* Copy the MLS range from the source context */
220 for (l = 0; l < 2; l++) {
221 dst->range.level[l].sens = src->range.level[l].sens;
222 rc = ebitmap_cpy(&dst->range.level[l].cat,
223 &src->range.level[l].cat);
224 if (rc)
225 break;
228 return rc;
232 * Set the MLS fields in the security context structure
233 * `context' based on the string representation in
234 * the string `*scontext'. Update `*scontext' to
235 * point to the end of the string representation of
236 * the MLS fields.
238 * This function modifies the string in place, inserting
239 * NULL characters to terminate the MLS fields.
241 * If a def_sid is provided and no MLS field is present,
242 * copy the MLS field of the associated default context.
243 * Used for upgraded to MLS systems where objects may lack
244 * MLS fields.
246 * Policy read-lock must be held for sidtab lookup.
249 int mls_context_to_sid(char oldc,
250 char **scontext,
251 struct context *context,
252 struct sidtab *s,
253 u32 def_sid)
256 char delim;
257 char *scontextp, *p, *rngptr;
258 struct level_datum *levdatum;
259 struct cat_datum *catdatum, *rngdatum;
260 int l, rc = -EINVAL;
262 if (!selinux_mls_enabled)
263 return 0;
266 * No MLS component to the security context, try and map to
267 * default if provided.
269 if (!oldc) {
270 struct context *defcon;
272 if (def_sid == SECSID_NULL)
273 goto out;
275 defcon = sidtab_search(s, def_sid);
276 if (!defcon)
277 goto out;
279 rc = mls_copy_context(context, defcon);
280 goto out;
283 /* Extract low sensitivity. */
284 scontextp = p = *scontext;
285 while (*p && *p != ':' && *p != '-')
286 p++;
288 delim = *p;
289 if (delim != 0)
290 *p++ = 0;
292 for (l = 0; l < 2; l++) {
293 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
294 if (!levdatum) {
295 rc = -EINVAL;
296 goto out;
299 context->range.level[l].sens = levdatum->level->sens;
301 if (delim == ':') {
302 /* Extract category set. */
303 while (1) {
304 scontextp = p;
305 while (*p && *p != ',' && *p != '-')
306 p++;
307 delim = *p;
308 if (delim != 0)
309 *p++ = 0;
311 /* Separate into range if exists */
312 if ((rngptr = strchr(scontextp, '.')) != NULL) {
313 /* Remove '.' */
314 *rngptr++ = 0;
317 catdatum = hashtab_search(policydb.p_cats.table,
318 scontextp);
319 if (!catdatum) {
320 rc = -EINVAL;
321 goto out;
324 rc = ebitmap_set_bit(&context->range.level[l].cat,
325 catdatum->value - 1, 1);
326 if (rc)
327 goto out;
329 /* If range, set all categories in range */
330 if (rngptr) {
331 int i;
333 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
334 if (!rngdatum) {
335 rc = -EINVAL;
336 goto out;
339 if (catdatum->value >= rngdatum->value) {
340 rc = -EINVAL;
341 goto out;
344 for (i = catdatum->value; i < rngdatum->value; i++) {
345 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
346 if (rc)
347 goto out;
351 if (delim != ',')
352 break;
355 if (delim == '-') {
356 /* Extract high sensitivity. */
357 scontextp = p;
358 while (*p && *p != ':')
359 p++;
361 delim = *p;
362 if (delim != 0)
363 *p++ = 0;
364 } else
365 break;
368 if (l == 0) {
369 context->range.level[1].sens = context->range.level[0].sens;
370 rc = ebitmap_cpy(&context->range.level[1].cat,
371 &context->range.level[0].cat);
372 if (rc)
373 goto out;
375 *scontext = ++p;
376 rc = 0;
377 out:
378 return rc;
382 * Copies the effective MLS range from `src' into `dst'.
384 static inline int mls_scopy_context(struct context *dst,
385 struct context *src)
387 int l, rc = 0;
389 /* Copy the MLS range from the source context */
390 for (l = 0; l < 2; l++) {
391 dst->range.level[l].sens = src->range.level[0].sens;
392 rc = ebitmap_cpy(&dst->range.level[l].cat,
393 &src->range.level[0].cat);
394 if (rc)
395 break;
398 return rc;
402 * Copies the MLS range `range' into `context'.
404 static inline int mls_range_set(struct context *context,
405 struct mls_range *range)
407 int l, rc = 0;
409 /* Copy the MLS range into the context */
410 for (l = 0; l < 2; l++) {
411 context->range.level[l].sens = range->level[l].sens;
412 rc = ebitmap_cpy(&context->range.level[l].cat,
413 &range->level[l].cat);
414 if (rc)
415 break;
418 return rc;
421 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
422 struct context *usercon)
424 if (selinux_mls_enabled) {
425 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
426 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
427 struct mls_level *user_low = &(user->range.level[0]);
428 struct mls_level *user_clr = &(user->range.level[1]);
429 struct mls_level *user_def = &(user->dfltlevel);
430 struct mls_level *usercon_sen = &(usercon->range.level[0]);
431 struct mls_level *usercon_clr = &(usercon->range.level[1]);
433 /* Honor the user's default level if we can */
434 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
435 *usercon_sen = *user_def;
436 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
437 *usercon_sen = *fromcon_sen;
438 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
439 *usercon_sen = *user_low;
440 } else
441 return -EINVAL;
443 /* Lower the clearance of available contexts
444 if the clearance of "fromcon" is lower than
445 that of the user's default clearance (but
446 only if the "fromcon" clearance dominates
447 the user's computed sensitivity level) */
448 if (mls_level_dom(user_clr, fromcon_clr)) {
449 *usercon_clr = *fromcon_clr;
450 } else if (mls_level_dom(fromcon_clr, user_clr)) {
451 *usercon_clr = *user_clr;
452 } else
453 return -EINVAL;
456 return 0;
460 * Convert the MLS fields in the security context
461 * structure `c' from the values specified in the
462 * policy `oldp' to the values specified in the policy `newp'.
464 int mls_convert_context(struct policydb *oldp,
465 struct policydb *newp,
466 struct context *c)
468 struct level_datum *levdatum;
469 struct cat_datum *catdatum;
470 struct ebitmap bitmap;
471 int l, i;
473 if (!selinux_mls_enabled)
474 return 0;
476 for (l = 0; l < 2; l++) {
477 levdatum = hashtab_search(newp->p_levels.table,
478 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
480 if (!levdatum)
481 return -EINVAL;
482 c->range.level[l].sens = levdatum->level->sens;
484 ebitmap_init(&bitmap);
485 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
486 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
487 int rc;
489 catdatum = hashtab_search(newp->p_cats.table,
490 oldp->p_cat_val_to_name[i - 1]);
491 if (!catdatum)
492 return -EINVAL;
493 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
494 if (rc)
495 return rc;
498 ebitmap_destroy(&c->range.level[l].cat);
499 c->range.level[l].cat = bitmap;
502 return 0;
505 int mls_compute_sid(struct context *scontext,
506 struct context *tcontext,
507 u16 tclass,
508 u32 specified,
509 struct context *newcontext)
511 if (!selinux_mls_enabled)
512 return 0;
514 switch (specified) {
515 case AVTAB_TRANSITION:
516 if (tclass == SECCLASS_PROCESS) {
517 struct range_trans *rangetr;
518 /* Look for a range transition rule. */
519 for (rangetr = policydb.range_tr; rangetr;
520 rangetr = rangetr->next) {
521 if (rangetr->dom == scontext->type &&
522 rangetr->type == tcontext->type) {
523 /* Set the range from the rule */
524 return mls_range_set(newcontext,
525 &rangetr->range);
529 /* Fallthrough */
530 case AVTAB_CHANGE:
531 if (tclass == SECCLASS_PROCESS)
532 /* Use the process MLS attributes. */
533 return mls_copy_context(newcontext, scontext);
534 else
535 /* Use the process effective MLS attributes. */
536 return mls_scopy_context(newcontext, scontext);
537 case AVTAB_MEMBER:
538 /* Only polyinstantiate the MLS attributes if
539 the type is being polyinstantiated */
540 if (newcontext->type != tcontext->type) {
541 /* Use the process effective MLS attributes. */
542 return mls_scopy_context(newcontext, scontext);
543 } else {
544 /* Use the related object MLS attributes. */
545 return mls_copy_context(newcontext, tcontext);
547 default:
548 return -EINVAL;
550 return -EINVAL;