Linux-2.6.12-rc2
[linux-2.6/kvm.git] / security / selinux / ss / mls.c
blob756036bcc243190858f997a0eb1af79942f3869d
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 "mls.h"
19 #include "policydb.h"
20 #include "services.h"
23 * Return the length in bytes for the MLS fields of the
24 * security context string representation of `context'.
26 int mls_compute_context_len(struct context * context)
28 int i, l, len, range;
30 if (!selinux_mls_enabled)
31 return 0;
33 len = 1; /* for the beginning ":" */
34 for (l = 0; l < 2; l++) {
35 range = 0;
36 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
38 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
39 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
40 if (range) {
41 range++;
42 continue;
45 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
46 range++;
47 } else {
48 if (range > 1)
49 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
50 range = 0;
53 /* Handle case where last category is the end of range */
54 if (range > 1)
55 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
57 if (l == 0) {
58 if (mls_level_eq(&context->range.level[0],
59 &context->range.level[1]))
60 break;
61 else
62 len++;
66 return len;
70 * Write the security context string representation of
71 * the MLS fields of `context' into the string `*scontext'.
72 * Update `*scontext' to point to the end of the MLS fields.
74 void mls_sid_to_context(struct context *context,
75 char **scontext)
77 char *scontextp;
78 int i, l, range, wrote_sep;
80 if (!selinux_mls_enabled)
81 return;
83 scontextp = *scontext;
85 *scontextp = ':';
86 scontextp++;
88 for (l = 0; l < 2; l++) {
89 range = 0;
90 wrote_sep = 0;
91 strcpy(scontextp,
92 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
93 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
95 /* categories */
96 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
97 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
98 if (range) {
99 range++;
100 continue;
103 if (!wrote_sep) {
104 *scontextp++ = ':';
105 wrote_sep = 1;
106 } else
107 *scontextp++ = ',';
108 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
109 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
110 range++;
111 } else {
112 if (range > 1) {
113 if (range > 2)
114 *scontextp++ = '.';
115 else
116 *scontextp++ = ',';
118 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
119 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
121 range = 0;
125 /* Handle case where last category is the end of range */
126 if (range > 1) {
127 if (range > 2)
128 *scontextp++ = '.';
129 else
130 *scontextp++ = ',';
132 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
133 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
136 if (l == 0) {
137 if (mls_level_eq(&context->range.level[0],
138 &context->range.level[1]))
139 break;
140 else {
141 *scontextp = '-';
142 scontextp++;
147 *scontext = scontextp;
148 return;
152 * Return 1 if the MLS fields in the security context
153 * structure `c' are valid. Return 0 otherwise.
155 int mls_context_isvalid(struct policydb *p, struct context *c)
157 struct level_datum *levdatum;
158 struct user_datum *usrdatum;
159 int i, l;
161 if (!selinux_mls_enabled)
162 return 1;
165 * MLS range validity checks: high must dominate low, low level must
166 * be valid (category set <-> sensitivity check), and high level must
167 * be valid (category set <-> sensitivity check)
169 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
170 /* High does not dominate low. */
171 return 0;
173 for (l = 0; l < 2; l++) {
174 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
175 return 0;
176 levdatum = hashtab_search(p->p_levels.table,
177 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
178 if (!levdatum)
179 return 0;
181 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
182 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
183 if (i > p->p_cats.nprim)
184 return 0;
185 if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
187 * Category may not be associated with
188 * sensitivity in low level.
190 return 0;
195 if (c->role == OBJECT_R_VAL)
196 return 1;
199 * User must be authorized for the MLS range.
201 if (!c->user || c->user > p->p_users.nprim)
202 return 0;
203 usrdatum = p->user_val_to_struct[c->user - 1];
204 if (!mls_range_contains(usrdatum->range, c->range))
205 return 0; /* user may not be associated with range */
207 return 1;
211 * Set the MLS fields in the security context structure
212 * `context' based on the string representation in
213 * the string `*scontext'. Update `*scontext' to
214 * point to the end of the string representation of
215 * the MLS fields.
217 * This function modifies the string in place, inserting
218 * NULL characters to terminate the MLS fields.
220 int mls_context_to_sid(char oldc,
221 char **scontext,
222 struct context *context)
225 char delim;
226 char *scontextp, *p, *rngptr;
227 struct level_datum *levdatum;
228 struct cat_datum *catdatum, *rngdatum;
229 int l, rc = -EINVAL;
231 if (!selinux_mls_enabled)
232 return 0;
234 /* No MLS component to the security context. */
235 if (!oldc)
236 goto out;
238 /* Extract low sensitivity. */
239 scontextp = p = *scontext;
240 while (*p && *p != ':' && *p != '-')
241 p++;
243 delim = *p;
244 if (delim != 0)
245 *p++ = 0;
247 for (l = 0; l < 2; l++) {
248 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
249 if (!levdatum) {
250 rc = -EINVAL;
251 goto out;
254 context->range.level[l].sens = levdatum->level->sens;
256 if (delim == ':') {
257 /* Extract category set. */
258 while (1) {
259 scontextp = p;
260 while (*p && *p != ',' && *p != '-')
261 p++;
262 delim = *p;
263 if (delim != 0)
264 *p++ = 0;
266 /* Separate into range if exists */
267 if ((rngptr = strchr(scontextp, '.')) != NULL) {
268 /* Remove '.' */
269 *rngptr++ = 0;
272 catdatum = hashtab_search(policydb.p_cats.table,
273 scontextp);
274 if (!catdatum) {
275 rc = -EINVAL;
276 goto out;
279 rc = ebitmap_set_bit(&context->range.level[l].cat,
280 catdatum->value - 1, 1);
281 if (rc)
282 goto out;
284 /* If range, set all categories in range */
285 if (rngptr) {
286 int i;
288 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
289 if (!rngdatum) {
290 rc = -EINVAL;
291 goto out;
294 if (catdatum->value >= rngdatum->value) {
295 rc = -EINVAL;
296 goto out;
299 for (i = catdatum->value; i < rngdatum->value; i++) {
300 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
301 if (rc)
302 goto out;
306 if (delim != ',')
307 break;
310 if (delim == '-') {
311 /* Extract high sensitivity. */
312 scontextp = p;
313 while (*p && *p != ':')
314 p++;
316 delim = *p;
317 if (delim != 0)
318 *p++ = 0;
319 } else
320 break;
323 if (l == 0) {
324 context->range.level[1].sens = context->range.level[0].sens;
325 rc = ebitmap_cpy(&context->range.level[1].cat,
326 &context->range.level[0].cat);
327 if (rc)
328 goto out;
330 *scontext = ++p;
331 rc = 0;
332 out:
333 return rc;
337 * Copies the MLS range from `src' into `dst'.
339 static inline int mls_copy_context(struct context *dst,
340 struct context *src)
342 int l, rc = 0;
344 /* Copy the MLS range from the source context */
345 for (l = 0; l < 2; l++) {
346 dst->range.level[l].sens = src->range.level[l].sens;
347 rc = ebitmap_cpy(&dst->range.level[l].cat,
348 &src->range.level[l].cat);
349 if (rc)
350 break;
353 return rc;
357 * Copies the effective MLS range from `src' into `dst'.
359 static inline int mls_scopy_context(struct context *dst,
360 struct context *src)
362 int l, rc = 0;
364 /* Copy the MLS range from the source context */
365 for (l = 0; l < 2; l++) {
366 dst->range.level[l].sens = src->range.level[0].sens;
367 rc = ebitmap_cpy(&dst->range.level[l].cat,
368 &src->range.level[0].cat);
369 if (rc)
370 break;
373 return rc;
377 * Copies the MLS range `range' into `context'.
379 static inline int mls_range_set(struct context *context,
380 struct mls_range *range)
382 int l, rc = 0;
384 /* Copy the MLS range into the context */
385 for (l = 0; l < 2; l++) {
386 context->range.level[l].sens = range->level[l].sens;
387 rc = ebitmap_cpy(&context->range.level[l].cat,
388 &range->level[l].cat);
389 if (rc)
390 break;
393 return rc;
396 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
397 struct context *usercon)
399 if (selinux_mls_enabled) {
400 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
401 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
402 struct mls_level *user_low = &(user->range.level[0]);
403 struct mls_level *user_clr = &(user->range.level[1]);
404 struct mls_level *user_def = &(user->dfltlevel);
405 struct mls_level *usercon_sen = &(usercon->range.level[0]);
406 struct mls_level *usercon_clr = &(usercon->range.level[1]);
408 /* Honor the user's default level if we can */
409 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
410 *usercon_sen = *user_def;
411 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
412 *usercon_sen = *fromcon_sen;
413 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
414 *usercon_sen = *user_low;
415 } else
416 return -EINVAL;
418 /* Lower the clearance of available contexts
419 if the clearance of "fromcon" is lower than
420 that of the user's default clearance (but
421 only if the "fromcon" clearance dominates
422 the user's computed sensitivity level) */
423 if (mls_level_dom(user_clr, fromcon_clr)) {
424 *usercon_clr = *fromcon_clr;
425 } else if (mls_level_dom(fromcon_clr, user_clr)) {
426 *usercon_clr = *user_clr;
427 } else
428 return -EINVAL;
431 return 0;
435 * Convert the MLS fields in the security context
436 * structure `c' from the values specified in the
437 * policy `oldp' to the values specified in the policy `newp'.
439 int mls_convert_context(struct policydb *oldp,
440 struct policydb *newp,
441 struct context *c)
443 struct level_datum *levdatum;
444 struct cat_datum *catdatum;
445 struct ebitmap bitmap;
446 int l, i;
448 if (!selinux_mls_enabled)
449 return 0;
451 for (l = 0; l < 2; l++) {
452 levdatum = hashtab_search(newp->p_levels.table,
453 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
455 if (!levdatum)
456 return -EINVAL;
457 c->range.level[l].sens = levdatum->level->sens;
459 ebitmap_init(&bitmap);
460 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
461 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
462 int rc;
464 catdatum = hashtab_search(newp->p_cats.table,
465 oldp->p_cat_val_to_name[i - 1]);
466 if (!catdatum)
467 return -EINVAL;
468 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
469 if (rc)
470 return rc;
473 ebitmap_destroy(&c->range.level[l].cat);
474 c->range.level[l].cat = bitmap;
477 return 0;
480 int mls_compute_sid(struct context *scontext,
481 struct context *tcontext,
482 u16 tclass,
483 u32 specified,
484 struct context *newcontext)
486 if (!selinux_mls_enabled)
487 return 0;
489 switch (specified) {
490 case AVTAB_TRANSITION:
491 if (tclass == SECCLASS_PROCESS) {
492 struct range_trans *rangetr;
493 /* Look for a range transition rule. */
494 for (rangetr = policydb.range_tr; rangetr;
495 rangetr = rangetr->next) {
496 if (rangetr->dom == scontext->type &&
497 rangetr->type == tcontext->type) {
498 /* Set the range from the rule */
499 return mls_range_set(newcontext,
500 &rangetr->range);
504 /* Fallthrough */
505 case AVTAB_CHANGE:
506 if (tclass == SECCLASS_PROCESS)
507 /* Use the process MLS attributes. */
508 return mls_copy_context(newcontext, scontext);
509 else
510 /* Use the process effective MLS attributes. */
511 return mls_scopy_context(newcontext, scontext);
512 case AVTAB_MEMBER:
513 /* Only polyinstantiate the MLS attributes if
514 the type is being polyinstantiated */
515 if (newcontext->type != tcontext->type) {
516 /* Use the process effective MLS attributes. */
517 return mls_scopy_context(newcontext, scontext);
518 } else {
519 /* Use the related object MLS attributes. */
520 return mls_copy_context(newcontext, tcontext);
522 default:
523 return -EINVAL;
525 return -EINVAL;