Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Implementation of the multi-level security (MLS) policy. | |
3 | * | |
4 | * Author : Stephen Smalley, <sds@epoch.ncsc.mil> | |
5 | */ | |
6 | /* | |
7 | * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> | |
8 | * | |
9 | * Support for enhanced MLS infrastructure. | |
10 | * | |
376bd9cb | 11 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
1da177e4 | 12 | */ |
7420ed23 VY |
13 | /* |
14 | * Updated: Hewlett-Packard <paul.moore@hp.com> | |
15 | * | |
02752760 | 16 | * Added support to import/export the MLS label from NetLabel |
7420ed23 VY |
17 | * |
18 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | |
19 | */ | |
1da177e4 LT |
20 | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/slab.h> | |
23 | #include <linux/string.h> | |
24 | #include <linux/errno.h> | |
02752760 | 25 | #include <net/netlabel.h> |
f5c1d5b2 | 26 | #include "sidtab.h" |
1da177e4 LT |
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 | */ | |
1a5e6f87 | 35 | int mls_compute_context_len(struct context *context) |
1da177e4 | 36 | { |
9fe79ad1 KK |
37 | int i, l, len, head, prev; |
38 | char *nm; | |
39 | struct ebitmap *e; | |
782ebb99 | 40 | struct ebitmap_node *node; |
1da177e4 LT |
41 | |
42 | if (!selinux_mls_enabled) | |
43 | return 0; | |
44 | ||
45 | len = 1; /* for the beginning ":" */ | |
46 | for (l = 0; l < 2; l++) { | |
9fe79ad1 KK |
47 | int index_sens = context->range.level[l].sens; |
48 | len += strlen(policydb.p_sens_val_to_name[index_sens - 1]); | |
1da177e4 | 49 | |
9fe79ad1 KK |
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 = policydb.p_cat_val_to_name[prev]; | |
59 | len += strlen(nm) + 1; | |
60 | } | |
61 | nm = policydb.p_cat_val_to_name[i]; | |
62 | len += strlen(nm) + 1; | |
63 | head = i; | |
1da177e4 | 64 | } |
9fe79ad1 KK |
65 | prev = i; |
66 | } | |
67 | if (prev != head) { | |
68 | nm = policydb.p_cat_val_to_name[prev]; | |
69 | len += strlen(nm) + 1; | |
1da177e4 | 70 | } |
1da177e4 LT |
71 | if (l == 0) { |
72 | if (mls_level_eq(&context->range.level[0], | |
9fe79ad1 | 73 | &context->range.level[1])) |
1da177e4 LT |
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 | */ | |
88 | void mls_sid_to_context(struct context *context, | |
1a5e6f87 | 89 | char **scontext) |
1da177e4 | 90 | { |
9fe79ad1 KK |
91 | char *scontextp, *nm; |
92 | int i, l, head, prev; | |
93 | struct ebitmap *e; | |
782ebb99 | 94 | struct ebitmap_node *node; |
1da177e4 LT |
95 | |
96 | if (!selinux_mls_enabled) | |
97 | return; | |
98 | ||
99 | scontextp = *scontext; | |
100 | ||
101 | *scontextp = ':'; | |
102 | scontextp++; | |
103 | ||
104 | for (l = 0; l < 2; l++) { | |
1da177e4 LT |
105 | strcpy(scontextp, |
106 | policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); | |
9fe79ad1 | 107 | scontextp += strlen(scontextp); |
1da177e4 LT |
108 | |
109 | /* categories */ | |
9fe79ad1 KK |
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) | |
1da177e4 LT |
118 | *scontextp++ = '.'; |
119 | else | |
120 | *scontextp++ = ','; | |
9fe79ad1 KK |
121 | nm = policydb.p_cat_val_to_name[prev]; |
122 | strcpy(scontextp, nm); | |
123 | scontextp += strlen(nm); | |
1da177e4 | 124 | } |
9fe79ad1 KK |
125 | if (prev < 0) |
126 | *scontextp++ = ':'; | |
127 | else | |
128 | *scontextp++ = ','; | |
129 | nm = policydb.p_cat_val_to_name[i]; | |
130 | strcpy(scontextp, nm); | |
131 | scontextp += strlen(nm); | |
132 | head = i; | |
1da177e4 | 133 | } |
9fe79ad1 | 134 | prev = i; |
1da177e4 LT |
135 | } |
136 | ||
9fe79ad1 KK |
137 | if (prev != head) { |
138 | if (prev - head > 1) | |
1da177e4 LT |
139 | *scontextp++ = '.'; |
140 | else | |
141 | *scontextp++ = ','; | |
9fe79ad1 KK |
142 | nm = policydb.p_cat_val_to_name[prev]; |
143 | strcpy(scontextp, nm); | |
144 | scontextp += strlen(nm); | |
1da177e4 LT |
145 | } |
146 | ||
147 | if (l == 0) { | |
148 | if (mls_level_eq(&context->range.level[0], | |
1a5e6f87 | 149 | &context->range.level[1])) |
1da177e4 | 150 | break; |
9fe79ad1 KK |
151 | else |
152 | *scontextp++ = '-'; | |
1da177e4 LT |
153 | } |
154 | } | |
155 | ||
156 | *scontext = scontextp; | |
157 | return; | |
158 | } | |
159 | ||
45e5421e SS |
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 | p->p_sens_val_to_name[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 | ||
1da177e4 LT |
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 | { | |
1da177e4 | 201 | struct user_datum *usrdatum; |
1da177e4 LT |
202 | |
203 | if (!selinux_mls_enabled) | |
204 | return 1; | |
205 | ||
45e5421e | 206 | if (!mls_range_isvalid(p, &c->range)) |
1da177e4 LT |
207 | return 0; |
208 | ||
1da177e4 LT |
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. | |
f5c1d5b2 JM |
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 | * | |
1da177e4 | 241 | */ |
12b29f34 SS |
242 | int mls_context_to_sid(struct policydb *pol, |
243 | char oldc, | |
1da177e4 | 244 | char **scontext, |
f5c1d5b2 JM |
245 | struct context *context, |
246 | struct sidtab *s, | |
247 | u32 def_sid) | |
1da177e4 LT |
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 | ||
e517a0cd SS |
256 | if (!selinux_mls_enabled) { |
257 | if (def_sid != SECSID_NULL && oldc) | |
ab5703b3 | 258 | *scontext += strlen(*scontext)+1; |
1da177e4 | 259 | return 0; |
e517a0cd | 260 | } |
1da177e4 | 261 | |
f5c1d5b2 JM |
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 | ||
0efc61ea | 276 | rc = mls_context_cpy(context, defcon); |
1da177e4 | 277 | goto out; |
f5c1d5b2 | 278 | } |
1da177e4 LT |
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++) { | |
12b29f34 | 290 | levdatum = hashtab_search(pol->p_levels.table, scontextp); |
1da177e4 LT |
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 */ | |
1a5e6f87 EP |
309 | rngptr = strchr(scontextp, '.'); |
310 | if (rngptr != NULL) { | |
1da177e4 LT |
311 | /* Remove '.' */ |
312 | *rngptr++ = 0; | |
313 | } | |
314 | ||
12b29f34 | 315 | catdatum = hashtab_search(pol->p_cats.table, |
1a5e6f87 | 316 | scontextp); |
1da177e4 LT |
317 | if (!catdatum) { |
318 | rc = -EINVAL; | |
319 | goto out; | |
320 | } | |
321 | ||
322 | rc = ebitmap_set_bit(&context->range.level[l].cat, | |
1a5e6f87 | 323 | catdatum->value - 1, 1); |
1da177e4 LT |
324 | if (rc) |
325 | goto out; | |
326 | ||
327 | /* If range, set all categories in range */ | |
328 | if (rngptr) { | |
329 | int i; | |
330 | ||
12b29f34 | 331 | rngdatum = hashtab_search(pol->p_cats.table, rngptr); |
1da177e4 LT |
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 | ||
376bd9cb DG |
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 | */ | |
385 | int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) | |
386 | { | |
387 | char *tmpstr, *freestr; | |
388 | int rc; | |
389 | ||
390 | if (!selinux_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 { | |
12b29f34 | 399 | rc = mls_context_to_sid(&policydb, ':', &tmpstr, context, |
1a5e6f87 | 400 | NULL, SECSID_NULL); |
376bd9cb DG |
401 | kfree(freestr); |
402 | } | |
403 | ||
404 | return rc; | |
405 | } | |
406 | ||
1da177e4 LT |
407 | /* |
408 | * Copies the MLS range `range' into `context'. | |
409 | */ | |
410 | static inline int mls_range_set(struct context *context, | |
1a5e6f87 | 411 | struct mls_range *range) |
1da177e4 LT |
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, | |
1a5e6f87 | 428 | struct context *usercon) |
1da177e4 LT |
429 | { |
430 | if (selinux_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) */ | |
1a5e6f87 | 454 | if (mls_level_dom(user_clr, fromcon_clr)) |
1da177e4 | 455 | *usercon_clr = *fromcon_clr; |
1a5e6f87 | 456 | else if (mls_level_dom(fromcon_clr, user_clr)) |
1da177e4 | 457 | *usercon_clr = *user_clr; |
1a5e6f87 | 458 | else |
1da177e4 LT |
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; | |
782ebb99 | 477 | struct ebitmap_node *node; |
1da177e4 LT |
478 | int l, i; |
479 | ||
480 | if (!selinux_mls_enabled) | |
481 | return 0; | |
482 | ||
483 | for (l = 0; l < 2; l++) { | |
484 | levdatum = hashtab_search(newp->p_levels.table, | |
485 | oldp->p_sens_val_to_name[c->range.level[l].sens - 1]); | |
486 | ||
487 | if (!levdatum) | |
488 | return -EINVAL; | |
489 | c->range.level[l].sens = levdatum->level->sens; | |
490 | ||
491 | ebitmap_init(&bitmap); | |
9fe79ad1 KK |
492 | ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) { |
493 | int rc; | |
494 | ||
495 | catdatum = hashtab_search(newp->p_cats.table, | |
496 | oldp->p_cat_val_to_name[i]); | |
497 | if (!catdatum) | |
498 | return -EINVAL; | |
499 | rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); | |
500 | if (rc) | |
501 | return rc; | |
1da177e4 LT |
502 | } |
503 | ebitmap_destroy(&c->range.level[l].cat); | |
504 | c->range.level[l].cat = bitmap; | |
505 | } | |
506 | ||
507 | return 0; | |
508 | } | |
509 | ||
510 | int mls_compute_sid(struct context *scontext, | |
511 | struct context *tcontext, | |
512 | u16 tclass, | |
513 | u32 specified, | |
514 | struct context *newcontext) | |
515 | { | |
f3f87714 DG |
516 | struct range_trans *rtr; |
517 | ||
1da177e4 LT |
518 | if (!selinux_mls_enabled) |
519 | return 0; | |
520 | ||
521 | switch (specified) { | |
522 | case AVTAB_TRANSITION: | |
f3f87714 DG |
523 | /* Look for a range transition rule. */ |
524 | for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { | |
525 | if (rtr->source_type == scontext->type && | |
526 | rtr->target_type == tcontext->type && | |
527 | rtr->target_class == tclass) { | |
528 | /* Set the range from the rule */ | |
529 | return mls_range_set(newcontext, | |
1a5e6f87 | 530 | &rtr->target_range); |
1da177e4 LT |
531 | } |
532 | } | |
533 | /* Fallthrough */ | |
534 | case AVTAB_CHANGE: | |
535 | if (tclass == SECCLASS_PROCESS) | |
536 | /* Use the process MLS attributes. */ | |
0efc61ea | 537 | return mls_context_cpy(newcontext, scontext); |
1da177e4 LT |
538 | else |
539 | /* Use the process effective MLS attributes. */ | |
0efc61ea | 540 | return mls_context_cpy_low(newcontext, scontext); |
1da177e4 | 541 | case AVTAB_MEMBER: |
2e08c0c1 EW |
542 | /* Use the process effective MLS attributes. */ |
543 | return mls_context_cpy_low(newcontext, scontext); | |
1da177e4 LT |
544 | default: |
545 | return -EINVAL; | |
546 | } | |
547 | return -EINVAL; | |
548 | } | |
549 | ||
02752760 | 550 | #ifdef CONFIG_NETLABEL |
7420ed23 | 551 | /** |
02752760 | 552 | * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel |
7420ed23 | 553 | * @context: the security context |
02752760 | 554 | * @secattr: the NetLabel security attributes |
7420ed23 VY |
555 | * |
556 | * Description: | |
02752760 PM |
557 | * Given the security context copy the low MLS sensitivity level into the |
558 | * NetLabel MLS sensitivity level field. | |
7420ed23 VY |
559 | * |
560 | */ | |
02752760 PM |
561 | void mls_export_netlbl_lvl(struct context *context, |
562 | struct netlbl_lsm_secattr *secattr) | |
7420ed23 VY |
563 | { |
564 | if (!selinux_mls_enabled) | |
565 | return; | |
566 | ||
16efd454 | 567 | secattr->attr.mls.lvl = context->range.level[0].sens - 1; |
02752760 | 568 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
7420ed23 VY |
569 | } |
570 | ||
571 | /** | |
02752760 | 572 | * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels |
7420ed23 | 573 | * @context: the security context |
02752760 | 574 | * @secattr: the NetLabel security attributes |
7420ed23 VY |
575 | * |
576 | * Description: | |
02752760 PM |
577 | * Given the security context and the NetLabel security attributes, copy the |
578 | * NetLabel MLS sensitivity level into the context. | |
7420ed23 VY |
579 | * |
580 | */ | |
02752760 PM |
581 | void mls_import_netlbl_lvl(struct context *context, |
582 | struct netlbl_lsm_secattr *secattr) | |
7420ed23 VY |
583 | { |
584 | if (!selinux_mls_enabled) | |
585 | return; | |
586 | ||
16efd454 | 587 | context->range.level[0].sens = secattr->attr.mls.lvl + 1; |
02752760 | 588 | context->range.level[1].sens = context->range.level[0].sens; |
7420ed23 VY |
589 | } |
590 | ||
591 | /** | |
02752760 | 592 | * mls_export_netlbl_cat - Export the MLS categories to NetLabel |
7420ed23 | 593 | * @context: the security context |
02752760 | 594 | * @secattr: the NetLabel security attributes |
7420ed23 VY |
595 | * |
596 | * Description: | |
02752760 PM |
597 | * Given the security context copy the low MLS categories into the NetLabel |
598 | * MLS category field. Returns zero on success, negative values on failure. | |
7420ed23 VY |
599 | * |
600 | */ | |
02752760 PM |
601 | int mls_export_netlbl_cat(struct context *context, |
602 | struct netlbl_lsm_secattr *secattr) | |
7420ed23 | 603 | { |
02752760 | 604 | int rc; |
7420ed23 | 605 | |
02752760 | 606 | if (!selinux_mls_enabled) |
7420ed23 VY |
607 | return 0; |
608 | ||
02752760 | 609 | rc = ebitmap_netlbl_export(&context->range.level[0].cat, |
16efd454 PM |
610 | &secattr->attr.mls.cat); |
611 | if (rc == 0 && secattr->attr.mls.cat != NULL) | |
02752760 | 612 | secattr->flags |= NETLBL_SECATTR_MLS_CAT; |
7420ed23 | 613 | |
7420ed23 VY |
614 | return rc; |
615 | } | |
616 | ||
617 | /** | |
02752760 | 618 | * mls_import_netlbl_cat - Import the MLS categories from NetLabel |
7420ed23 | 619 | * @context: the security context |
02752760 | 620 | * @secattr: the NetLabel security attributes |
7420ed23 VY |
621 | * |
622 | * Description: | |
02752760 PM |
623 | * Copy the NetLabel security attributes into the SELinux context; since the |
624 | * NetLabel security attribute only contains a single MLS category use it for | |
625 | * both the low and high categories of the context. Returns zero on success, | |
626 | * negative values on failure. | |
7420ed23 VY |
627 | * |
628 | */ | |
02752760 PM |
629 | int mls_import_netlbl_cat(struct context *context, |
630 | struct netlbl_lsm_secattr *secattr) | |
7420ed23 | 631 | { |
02752760 | 632 | int rc; |
7420ed23 VY |
633 | |
634 | if (!selinux_mls_enabled) | |
635 | return 0; | |
636 | ||
02752760 | 637 | rc = ebitmap_netlbl_import(&context->range.level[0].cat, |
16efd454 | 638 | secattr->attr.mls.cat); |
02752760 PM |
639 | if (rc != 0) |
640 | goto import_netlbl_cat_failure; | |
641 | ||
642 | rc = ebitmap_cpy(&context->range.level[1].cat, | |
643 | &context->range.level[0].cat); | |
644 | if (rc != 0) | |
645 | goto import_netlbl_cat_failure; | |
7420ed23 VY |
646 | |
647 | return 0; | |
648 | ||
02752760 | 649 | import_netlbl_cat_failure: |
7420ed23 VY |
650 | ebitmap_destroy(&context->range.level[0].cat); |
651 | ebitmap_destroy(&context->range.level[1].cat); | |
652 | return rc; | |
653 | } | |
02752760 | 654 | #endif /* CONFIG_NETLABEL */ |