diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 135 |
1 files changed, 113 insertions, 22 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 24caaeec8894..a91c961ba38b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -246,6 +246,7 @@ static int superblock_alloc_security(struct super_block *sb) | |||
246 | sbsec->sb = sb; | 246 | sbsec->sb = sb; |
247 | sbsec->sid = SECINITSID_UNLABELED; | 247 | sbsec->sid = SECINITSID_UNLABELED; |
248 | sbsec->def_sid = SECINITSID_FILE; | 248 | sbsec->def_sid = SECINITSID_FILE; |
249 | sbsec->mntpoint_sid = SECINITSID_UNLABELED; | ||
249 | sb->s_security = sbsec; | 250 | sb->s_security = sbsec; |
250 | 251 | ||
251 | return 0; | 252 | return 0; |
@@ -319,19 +320,53 @@ enum { | |||
319 | Opt_context = 1, | 320 | Opt_context = 1, |
320 | Opt_fscontext = 2, | 321 | Opt_fscontext = 2, |
321 | Opt_defcontext = 4, | 322 | Opt_defcontext = 4, |
323 | Opt_rootcontext = 8, | ||
322 | }; | 324 | }; |
323 | 325 | ||
324 | static match_table_t tokens = { | 326 | static match_table_t tokens = { |
325 | {Opt_context, "context=%s"}, | 327 | {Opt_context, "context=%s"}, |
326 | {Opt_fscontext, "fscontext=%s"}, | 328 | {Opt_fscontext, "fscontext=%s"}, |
327 | {Opt_defcontext, "defcontext=%s"}, | 329 | {Opt_defcontext, "defcontext=%s"}, |
330 | {Opt_rootcontext, "rootcontext=%s"}, | ||
328 | }; | 331 | }; |
329 | 332 | ||
330 | #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" | 333 | #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" |
331 | 334 | ||
335 | static int may_context_mount_sb_relabel(u32 sid, | ||
336 | struct superblock_security_struct *sbsec, | ||
337 | struct task_security_struct *tsec) | ||
338 | { | ||
339 | int rc; | ||
340 | |||
341 | rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | ||
342 | FILESYSTEM__RELABELFROM, NULL); | ||
343 | if (rc) | ||
344 | return rc; | ||
345 | |||
346 | rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, | ||
347 | FILESYSTEM__RELABELTO, NULL); | ||
348 | return rc; | ||
349 | } | ||
350 | |||
351 | static int may_context_mount_inode_relabel(u32 sid, | ||
352 | struct superblock_security_struct *sbsec, | ||
353 | struct task_security_struct *tsec) | ||
354 | { | ||
355 | int rc; | ||
356 | rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | ||
357 | FILESYSTEM__RELABELFROM, NULL); | ||
358 | if (rc) | ||
359 | return rc; | ||
360 | |||
361 | rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, | ||
362 | FILESYSTEM__ASSOCIATE, NULL); | ||
363 | return rc; | ||
364 | } | ||
365 | |||
332 | static int try_context_mount(struct super_block *sb, void *data) | 366 | static int try_context_mount(struct super_block *sb, void *data) |
333 | { | 367 | { |
334 | char *context = NULL, *defcontext = NULL; | 368 | char *context = NULL, *defcontext = NULL; |
369 | char *fscontext = NULL, *rootcontext = NULL; | ||
335 | const char *name; | 370 | const char *name; |
336 | u32 sid; | 371 | u32 sid; |
337 | int alloc = 0, rc = 0, seen = 0; | 372 | int alloc = 0, rc = 0, seen = 0; |
@@ -374,7 +409,7 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
374 | 409 | ||
375 | switch (token) { | 410 | switch (token) { |
376 | case Opt_context: | 411 | case Opt_context: |
377 | if (seen) { | 412 | if (seen & (Opt_context|Opt_defcontext)) { |
378 | rc = -EINVAL; | 413 | rc = -EINVAL; |
379 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); | 414 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); |
380 | goto out_free; | 415 | goto out_free; |
@@ -390,13 +425,13 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
390 | break; | 425 | break; |
391 | 426 | ||
392 | case Opt_fscontext: | 427 | case Opt_fscontext: |
393 | if (seen & (Opt_context|Opt_fscontext)) { | 428 | if (seen & Opt_fscontext) { |
394 | rc = -EINVAL; | 429 | rc = -EINVAL; |
395 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); | 430 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); |
396 | goto out_free; | 431 | goto out_free; |
397 | } | 432 | } |
398 | context = match_strdup(&args[0]); | 433 | fscontext = match_strdup(&args[0]); |
399 | if (!context) { | 434 | if (!fscontext) { |
400 | rc = -ENOMEM; | 435 | rc = -ENOMEM; |
401 | goto out_free; | 436 | goto out_free; |
402 | } | 437 | } |
@@ -405,6 +440,22 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
405 | seen |= Opt_fscontext; | 440 | seen |= Opt_fscontext; |
406 | break; | 441 | break; |
407 | 442 | ||
443 | case Opt_rootcontext: | ||
444 | if (seen & Opt_rootcontext) { | ||
445 | rc = -EINVAL; | ||
446 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); | ||
447 | goto out_free; | ||
448 | } | ||
449 | rootcontext = match_strdup(&args[0]); | ||
450 | if (!rootcontext) { | ||
451 | rc = -ENOMEM; | ||
452 | goto out_free; | ||
453 | } | ||
454 | if (!alloc) | ||
455 | alloc = 1; | ||
456 | seen |= Opt_rootcontext; | ||
457 | break; | ||
458 | |||
408 | case Opt_defcontext: | 459 | case Opt_defcontext: |
409 | if (sbsec->behavior != SECURITY_FS_USE_XATTR) { | 460 | if (sbsec->behavior != SECURITY_FS_USE_XATTR) { |
410 | rc = -EINVAL; | 461 | rc = -EINVAL; |
@@ -441,6 +492,28 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
441 | if (!seen) | 492 | if (!seen) |
442 | goto out; | 493 | goto out; |
443 | 494 | ||
495 | /* sets the context of the superblock for the fs being mounted. */ | ||
496 | if (fscontext) { | ||
497 | rc = security_context_to_sid(fscontext, strlen(fscontext), &sid); | ||
498 | if (rc) { | ||
499 | printk(KERN_WARNING "SELinux: security_context_to_sid" | ||
500 | "(%s) failed for (dev %s, type %s) errno=%d\n", | ||
501 | fscontext, sb->s_id, name, rc); | ||
502 | goto out_free; | ||
503 | } | ||
504 | |||
505 | rc = may_context_mount_sb_relabel(sid, sbsec, tsec); | ||
506 | if (rc) | ||
507 | goto out_free; | ||
508 | |||
509 | sbsec->sid = sid; | ||
510 | } | ||
511 | |||
512 | /* | ||
513 | * Switch to using mount point labeling behavior. | ||
514 | * sets the label used on all file below the mountpoint, and will set | ||
515 | * the superblock context if not already set. | ||
516 | */ | ||
444 | if (context) { | 517 | if (context) { |
445 | rc = security_context_to_sid(context, strlen(context), &sid); | 518 | rc = security_context_to_sid(context, strlen(context), &sid); |
446 | if (rc) { | 519 | if (rc) { |
@@ -450,20 +523,38 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
450 | goto out_free; | 523 | goto out_free; |
451 | } | 524 | } |
452 | 525 | ||
453 | rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | 526 | if (!fscontext) { |
454 | FILESYSTEM__RELABELFROM, NULL); | 527 | rc = may_context_mount_sb_relabel(sid, sbsec, tsec); |
455 | if (rc) | 528 | if (rc) |
529 | goto out_free; | ||
530 | sbsec->sid = sid; | ||
531 | } else { | ||
532 | rc = may_context_mount_inode_relabel(sid, sbsec, tsec); | ||
533 | if (rc) | ||
534 | goto out_free; | ||
535 | } | ||
536 | sbsec->mntpoint_sid = sid; | ||
537 | |||
538 | sbsec->behavior = SECURITY_FS_USE_MNTPOINT; | ||
539 | } | ||
540 | |||
541 | if (rootcontext) { | ||
542 | struct inode *inode = sb->s_root->d_inode; | ||
543 | struct inode_security_struct *isec = inode->i_security; | ||
544 | rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid); | ||
545 | if (rc) { | ||
546 | printk(KERN_WARNING "SELinux: security_context_to_sid" | ||
547 | "(%s) failed for (dev %s, type %s) errno=%d\n", | ||
548 | rootcontext, sb->s_id, name, rc); | ||
456 | goto out_free; | 549 | goto out_free; |
550 | } | ||
457 | 551 | ||
458 | rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, | 552 | rc = may_context_mount_inode_relabel(sid, sbsec, tsec); |
459 | FILESYSTEM__RELABELTO, NULL); | ||
460 | if (rc) | 553 | if (rc) |
461 | goto out_free; | 554 | goto out_free; |
462 | 555 | ||
463 | sbsec->sid = sid; | 556 | isec->sid = sid; |
464 | 557 | isec->initialized = 1; | |
465 | if (seen & Opt_context) | ||
466 | sbsec->behavior = SECURITY_FS_USE_MNTPOINT; | ||
467 | } | 558 | } |
468 | 559 | ||
469 | if (defcontext) { | 560 | if (defcontext) { |
@@ -478,13 +569,7 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
478 | if (sid == sbsec->def_sid) | 569 | if (sid == sbsec->def_sid) |
479 | goto out_free; | 570 | goto out_free; |
480 | 571 | ||
481 | rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | 572 | rc = may_context_mount_inode_relabel(sid, sbsec, tsec); |
482 | FILESYSTEM__RELABELFROM, NULL); | ||
483 | if (rc) | ||
484 | goto out_free; | ||
485 | |||
486 | rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, | ||
487 | FILESYSTEM__ASSOCIATE, NULL); | ||
488 | if (rc) | 573 | if (rc) |
489 | goto out_free; | 574 | goto out_free; |
490 | 575 | ||
@@ -495,6 +580,8 @@ out_free: | |||
495 | if (alloc) { | 580 | if (alloc) { |
496 | kfree(context); | 581 | kfree(context); |
497 | kfree(defcontext); | 582 | kfree(defcontext); |
583 | kfree(fscontext); | ||
584 | kfree(rootcontext); | ||
498 | } | 585 | } |
499 | out: | 586 | out: |
500 | return rc; | 587 | return rc; |
@@ -876,8 +963,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
876 | goto out; | 963 | goto out; |
877 | isec->sid = sid; | 964 | isec->sid = sid; |
878 | break; | 965 | break; |
966 | case SECURITY_FS_USE_MNTPOINT: | ||
967 | isec->sid = sbsec->mntpoint_sid; | ||
968 | break; | ||
879 | default: | 969 | default: |
880 | /* Default to the fs SID. */ | 970 | /* Default to the fs superblock SID. */ |
881 | isec->sid = sbsec->sid; | 971 | isec->sid = sbsec->sid; |
882 | 972 | ||
883 | if (sbsec->proc) { | 973 | if (sbsec->proc) { |
@@ -1843,7 +1933,8 @@ static inline int selinux_option(char *option, int len) | |||
1843 | { | 1933 | { |
1844 | return (match_prefix("context=", sizeof("context=")-1, option, len) || | 1934 | return (match_prefix("context=", sizeof("context=")-1, option, len) || |
1845 | match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || | 1935 | match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || |
1846 | match_prefix("defcontext=", sizeof("defcontext=")-1, option, len)); | 1936 | match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) || |
1937 | match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len)); | ||
1847 | } | 1938 | } |
1848 | 1939 | ||
1849 | static inline void take_option(char **to, char *from, int *first, int len) | 1940 | static inline void take_option(char **to, char *from, int *first, int len) |