1 /*
2 * Implementation of the multi-level security (MLS) policy.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6
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 */
14
15 /* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
16
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"
25
26 /*
27 * Return the length in bytes for the MLS fields of the
28 * security context string representation of `context'.
29 */
mls_compute_context_len(struct context * context)30 int mls_compute_context_len(struct context * context)
31 {
32 int i, l, len, head, prev;
33 char *nm;
34 struct ebitmap *e;
35 struct ebitmap_node *node;
36
37 if ( !flask_mls_enabled )
38 return 0;
39
40 len = 1; /* for the beginning ":" */
41 for ( l = 0; l < 2; l++ )
42 {
43 int index_sens = context->range.level[l].sens;
44 len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
45
46 /* categories */
47 head = -2;
48 prev = -2;
49 e = &context->range.level[l].cat;
50 ebitmap_for_each_positive_bit(e, node, i)
51 {
52 if ( i - prev > 1 )
53 {
54 /* one or more negative bits are skipped */
55 if ( head != prev )
56 {
57 nm = policydb.p_cat_val_to_name[prev];
58 len += strlen(nm) + 1;
59 }
60 nm = policydb.p_cat_val_to_name[i];
61 len += strlen(nm) + 1;
62 head = i;
63 }
64 prev = i;
65 }
66 if ( prev != head )
67 {
68 nm = policydb.p_cat_val_to_name[prev];
69 len += strlen(nm) + 1;
70 }
71 if ( l == 0 )
72 {
73 if ( mls_level_eq(&context->range.level[0],
74 &context->range.level[1]) )
75 break;
76 else
77 len++;
78 }
79 }
80
81 return len;
82 }
83
84 /*
85 * Write the security context string representation of
86 * the MLS fields of `context' into the string `*scontext'.
87 * Update `*scontext' to point to the end of the MLS fields.
88 */
mls_sid_to_context(struct context * context,char ** scontext)89 void mls_sid_to_context(struct context *context, 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 ( !flask_mls_enabled )
97 return;
98
99 scontextp = *scontext;
100
101 *scontextp = ':';
102 scontextp++;
103
104 for ( l = 0; l < 2; l++ )
105 {
106 memcpy(scontextp,
107 policydb.p_sens_val_to_name[context->range.level[l].sens - 1],
108 strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1])+1);
109 scontextp += strlen(scontextp);
110
111 /* categories */
112 head = -2;
113 prev = -2;
114 e = &context->range.level[l].cat;
115 ebitmap_for_each_positive_bit(e, node, i)
116 {
117 if ( i - prev > 1 )
118 {
119 /* one or more negative bits are skipped */
120 if ( prev != head )
121 {
122 if ( prev - head > 1 )
123 *scontextp++ = '.';
124 else
125 *scontextp++ = ',';
126 nm = policydb.p_cat_val_to_name[prev];
127 memcpy(scontextp, nm, strlen(nm)+1);
128 scontextp += strlen(nm);
129 }
130 if ( prev < 0 )
131 *scontextp++ = ':';
132 else
133 *scontextp++ = ',';
134 nm = policydb.p_cat_val_to_name[i];
135 memcpy(scontextp, nm, strlen(nm)+1);
136 scontextp += strlen(nm);
137 head = i;
138 }
139 prev = i;
140 }
141
142 if ( prev != head )
143 {
144 if ( prev - head > 1 )
145 *scontextp++ = '.';
146 else
147 *scontextp++ = ',';
148 nm = policydb.p_cat_val_to_name[prev];
149 memcpy(scontextp, nm, strlen(nm)+1);
150 scontextp += strlen(nm);
151 }
152
153 if ( l == 0 )
154 {
155 if ( mls_level_eq(&context->range.level[0],
156 &context->range.level[1]) )
157 break;
158 else
159 {
160 *scontextp = '-';
161 scontextp++;
162 }
163 }
164 }
165
166 *scontext = scontextp;
167 return;
168 }
169
mls_level_isvalid(struct policydb * p,struct mls_level * l)170 int mls_level_isvalid(struct policydb *p, struct mls_level *l)
171 {
172 struct level_datum *levdatum;
173 struct ebitmap_node *node;
174 int i;
175
176 if ( !l->sens || l->sens > p->p_levels.nprim )
177 return 0;
178 levdatum = hashtab_search(p->p_levels.table,
179 p->p_sens_val_to_name[l->sens - 1]);
180 if ( !levdatum )
181 return 0;
182
183 ebitmap_for_each_positive_bit(&l->cat, node, i)
184 {
185 if ( i > p->p_cats.nprim )
186 return 0;
187 if ( !ebitmap_get_bit(&levdatum->level->cat, i) )
188 {
189 /*
190 * Category may not be associated with
191 * sensitivity.
192 */
193 return 0;
194 }
195 }
196
197 return 1;
198 }
199
mls_range_isvalid(struct policydb * p,struct mls_range * r)200 int mls_range_isvalid(struct policydb *p, struct mls_range *r)
201 {
202 return ( mls_level_isvalid(p, &r->level[0]) &&
203 mls_level_isvalid(p, &r->level[1]) &&
204 mls_level_dom(&r->level[1], &r->level[0]));
205 }
206
207 /*
208 * Return 1 if the MLS fields in the security context
209 * structure `c' are valid. Return 0 otherwise.
210 */
mls_context_isvalid(struct policydb * p,struct context * c)211 int mls_context_isvalid(struct policydb *p, struct context *c)
212 {
213 struct user_datum *usrdatum;
214
215 if ( !flask_mls_enabled )
216 return 1;
217
218 if ( !mls_range_isvalid(p, &c->range) )
219 return 0;
220
221 if ( c->role == OBJECT_R_VAL )
222 return 1;
223
224 /*
225 * User must be authorized for the MLS range.
226 */
227 if ( !c->user || c->user > p->p_users.nprim )
228 return 0;
229 usrdatum = p->user_val_to_struct[c->user - 1];
230 if ( !mls_range_contains(usrdatum->range, c->range) )
231 return 0; /* user may not be associated with range */
232
233 return 1;
234 }
235
236 /*
237 * Set the MLS fields in the security context structure
238 * `context' based on the string representation in
239 * the string `*scontext'. Update `*scontext' to
240 * point to the end of the string representation of
241 * the MLS fields.
242 *
243 * This function modifies the string in place, inserting
244 * NULL characters to terminate the MLS fields.
245 *
246 * Policy read-lock must be held for sidtab lookup.
247 *
248 */
mls_context_to_sid(char oldc,char ** scontext,struct context * context,struct sidtab * s)249 int mls_context_to_sid(char oldc, char **scontext,
250 struct context *context, struct sidtab *s)
251 {
252
253 char delim;
254 char *scontextp, *p, *rngptr;
255 struct level_datum *levdatum;
256 struct cat_datum *catdatum, *rngdatum;
257 int l, rc = -EINVAL;
258
259 if ( !flask_mls_enabled )
260 return 0;
261
262 /*
263 * No MLS component to the security context -> error.
264 */
265 if ( !oldc )
266 goto out;
267
268 /* Extract low sensitivity. */
269 scontextp = p = *scontext;
270 while ( *p && *p != ':' && *p != '-' )
271 p++;
272
273 delim = *p;
274 if ( delim != 0 )
275 *p++ = 0;
276
277 for ( l = 0; l < 2; l++ )
278 {
279 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
280 if ( !levdatum )
281 {
282 rc = -EINVAL;
283 goto out;
284 }
285
286 context->range.level[l].sens = levdatum->level->sens;
287
288 if ( delim == ':' )
289 {
290 /* Extract category set. */
291 while ( 1 )
292 {
293 scontextp = p;
294 while ( *p && *p != ',' && *p != '-' )
295 p++;
296 delim = *p;
297 if ( delim != 0 )
298 *p++ = 0;
299
300 /* Separate into range if exists */
301 if ( (rngptr = strchr(scontextp, '.')) != NULL )
302 {
303 /* Remove '.' */
304 *rngptr++ = 0;
305 }
306
307 catdatum = hashtab_search(policydb.p_cats.table, scontextp);
308 if ( !catdatum )
309 {
310 rc = -EINVAL;
311 goto out;
312 }
313
314 rc = ebitmap_set_bit(&context->range.level[l].cat,
315 catdatum->value - 1, 1);
316 if ( rc )
317 goto out;
318
319 /* If range, set all categories in range */
320 if ( rngptr )
321 {
322 int i;
323
324 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
325 if ( !rngdatum )
326 {
327 rc = -EINVAL;
328 goto out;
329 }
330
331 if ( catdatum->value >= rngdatum->value )
332 {
333 rc = -EINVAL;
334 goto out;
335 }
336
337 for ( i = catdatum->value; i < rngdatum->value; i++ )
338 {
339 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
340 if ( rc )
341 goto out;
342 }
343 }
344
345 if ( delim != ',' )
346 break;
347 }
348 }
349 if ( delim == '-' )
350 {
351 /* Extract high sensitivity. */
352 scontextp = p;
353 while ( *p && *p != ':' )
354 p++;
355
356 delim = *p;
357 if ( delim != 0 )
358 *p++ = 0;
359 }
360 else
361 break;
362 }
363
364 if ( l == 0 )
365 {
366 context->range.level[1].sens = context->range.level[0].sens;
367 rc = ebitmap_cpy(&context->range.level[1].cat,
368 &context->range.level[0].cat);
369 if ( rc )
370 goto out;
371 }
372 *scontext = ++p;
373 rc = 0;
374 out:
375 return rc;
376 }
377
378 /*
379 * Copies the MLS range `range' into `context'.
380 */
mls_range_set(struct context * context,struct mls_range * range)381 static inline int mls_range_set(struct context *context,
382 struct mls_range *range)
383 {
384 int l, rc = 0;
385
386 /* Copy the MLS range into the context */
387 for ( l = 0; l < 2; l++ )
388 {
389 context->range.level[l].sens = range->level[l].sens;
390 rc = ebitmap_cpy(&context->range.level[l].cat,
391 &range->level[l].cat);
392 if ( rc )
393 break;
394 }
395
396 return rc;
397 }
398
399 /*
400 * Convert the MLS fields in the security context
401 * structure `c' from the values specified in the
402 * policy `oldp' to the values specified in the policy `newp'.
403 */
mls_convert_context(struct policydb * oldp,struct policydb * newp,struct context * c)404 int mls_convert_context(struct policydb *oldp, struct policydb *newp,
405 struct context *c)
406 {
407 struct level_datum *levdatum;
408 struct cat_datum *catdatum;
409 struct ebitmap bitmap;
410 struct ebitmap_node *node;
411 int l, i;
412
413 if ( !flask_mls_enabled )
414 return 0;
415
416 for ( l = 0; l < 2; l++ )
417 {
418 levdatum = hashtab_search(newp->p_levels.table,
419 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
420
421 if ( !levdatum )
422 return -EINVAL;
423 c->range.level[l].sens = levdatum->level->sens;
424
425 ebitmap_init(&bitmap);
426 ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i)
427 {
428 int rc;
429
430 catdatum = hashtab_search(newp->p_cats.table,
431 oldp->p_cat_val_to_name[i]);
432 if ( !catdatum )
433 return -EINVAL;
434 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
435 if ( rc )
436 return rc;
437 }
438 ebitmap_destroy(&c->range.level[l].cat);
439 c->range.level[l].cat = bitmap;
440 }
441
442 return 0;
443 }
444
mls_compute_sid(struct context * scontext,struct context * tcontext,u16 tclass,u32 specified,struct context * newcontext)445 int mls_compute_sid(struct context *scontext, struct context *tcontext,
446 u16 tclass, u32 specified, struct context *newcontext)
447 {
448 struct range_trans *rtr;
449
450 if ( !flask_mls_enabled )
451 return 0;
452
453 switch ( specified )
454 {
455 case AVTAB_TRANSITION:
456 /* Look for a range transition rule. */
457 for (rtr = policydb.range_tr; rtr; rtr = rtr->next)
458 {
459 if (rtr->source_type == scontext->type &&
460 rtr->target_type == tcontext->type &&
461 rtr->target_class == tclass)
462 {
463 /* Set the range from the rule */
464 return mls_range_set(newcontext,
465 &rtr->target_range);
466 }
467 }
468 /* Fallthrough */
469 case AVTAB_CHANGE:
470 if ( tclass == SECCLASS_DOMAIN )
471 /* Use the process MLS attributes. */
472 return mls_context_cpy(newcontext, scontext);
473 else
474 /* Use the process effective MLS attributes. */
475 return mls_context_cpy_low(newcontext, scontext);
476 case AVTAB_MEMBER:
477 /* Use the process effective MLS attributes. */
478 return mls_context_cpy_low(newcontext, scontext);
479 default:
480 return -EINVAL;
481 }
482 return -EINVAL;
483 }
484
485