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