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