aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2007-11-30 13:00:35 -0500
committerJames Morris <jmorris@namei.org>2008-01-24 19:29:46 -0500
commitc9180a57a9ab2d5525faf8815a332364ee9e89b7 (patch)
treec677ec33735f3529d478a2b71fcc732d4fe59adf /security
parent19c5fc198c369bb00f3ed9716ef40648865d8d94 (diff)
Security: add get, set, and cloning of superblock security information
Adds security_get_sb_mnt_opts, security_set_sb_mnt_opts, and security_clont_sb_mnt_opts to the LSM and to SELinux. This will allow filesystems to directly own and control all of their mount options if they so choose. This interface deals only with option identifiers and strings so it should generic enough for any LSM which may come in the future. Filesystems which pass text mount data around in the kernel (almost all of them) need not currently make use of this interface when dealing with SELinux since it will still parse those strings as it always has. I assume future LSM's would do the same. NFS is the primary FS which does not use text mount data and thus must make use of this interface. An LSM would need to implement these functions only if they had mount time options, such as selinux has context= or fscontext=. If the LSM has no mount time options they could simply not implement and let the dummy ops take care of things. An LSM other than SELinux would need to define new option numbers in security.h and any FS which decides to own there own security options would need to be patched to use this new interface for every possible LSM. This is because it was stated to me very clearly that LSM's should not attempt to understand FS mount data and the burdon to understand security should be in the FS which owns the options. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Stephen D. Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/dummy.c26
-rw-r--r--security/security.c20
-rw-r--r--security/selinux/hooks.c748
-rw-r--r--security/selinux/include/objsec.h1
4 files changed, 541 insertions, 254 deletions
diff --git a/security/dummy.c b/security/dummy.c
index 3ccfbbe973b6..a3b29d0d00e5 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -245,6 +245,29 @@ static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata
245 return; 245 return;
246} 246}
247 247
248static int dummy_sb_get_mnt_opts(const struct super_block *sb, char ***mount_options,
249 int **flags, int *num_opts)
250{
251 *mount_options = NULL;
252 *flags = NULL;
253 *num_opts = 0;
254 return 0;
255}
256
257static int dummy_sb_set_mnt_opts(struct super_block *sb, char **mount_options,
258 int *flags, int num_opts)
259{
260 if (unlikely(num_opts))
261 return -EOPNOTSUPP;
262 return 0;
263}
264
265static void dummy_sb_clone_mnt_opts(const struct super_block *oldsb,
266 struct super_block *newsb)
267{
268 return;
269}
270
248static int dummy_inode_alloc_security (struct inode *inode) 271static int dummy_inode_alloc_security (struct inode *inode)
249{ 272{
250 return 0; 273 return 0;
@@ -998,6 +1021,9 @@ void security_fixup_ops (struct security_operations *ops)
998 set_to_dummy_if_null(ops, sb_post_addmount); 1021 set_to_dummy_if_null(ops, sb_post_addmount);
999 set_to_dummy_if_null(ops, sb_pivotroot); 1022 set_to_dummy_if_null(ops, sb_pivotroot);
1000 set_to_dummy_if_null(ops, sb_post_pivotroot); 1023 set_to_dummy_if_null(ops, sb_post_pivotroot);
1024 set_to_dummy_if_null(ops, sb_get_mnt_opts);
1025 set_to_dummy_if_null(ops, sb_set_mnt_opts);
1026 set_to_dummy_if_null(ops, sb_clone_mnt_opts);
1001 set_to_dummy_if_null(ops, inode_alloc_security); 1027 set_to_dummy_if_null(ops, inode_alloc_security);
1002 set_to_dummy_if_null(ops, inode_free_security); 1028 set_to_dummy_if_null(ops, inode_free_security);
1003 set_to_dummy_if_null(ops, inode_init_security); 1029 set_to_dummy_if_null(ops, inode_init_security);
diff --git a/security/security.c b/security/security.c
index 0e1f1f124368..b13b54f0af85 100644
--- a/security/security.c
+++ b/security/security.c
@@ -308,6 +308,26 @@ void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_
308 security_ops->sb_post_pivotroot(old_nd, new_nd); 308 security_ops->sb_post_pivotroot(old_nd, new_nd);
309} 309}
310 310
311int security_sb_get_mnt_opts(const struct super_block *sb,
312 char ***mount_options,
313 int **flags, int *num_opts)
314{
315 return security_ops->sb_get_mnt_opts(sb, mount_options, flags, num_opts);
316}
317
318int security_sb_set_mnt_opts(struct super_block *sb,
319 char **mount_options,
320 int *flags, int num_opts)
321{
322 return security_ops->sb_set_mnt_opts(sb, mount_options, flags, num_opts);
323}
324
325void security_sb_clone_mnt_opts(const struct super_block *oldsb,
326 struct super_block *newsb)
327{
328 security_ops->sb_clone_mnt_opts(oldsb, newsb);
329}
330
311int security_inode_alloc(struct inode *inode) 331int security_inode_alloc(struct inode *inode)
312{ 332{
313 inode->i_security = NULL; 333 inode->i_security = NULL;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9f3124b08867..233c8b97462f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -82,6 +82,8 @@
82#define XATTR_SELINUX_SUFFIX "selinux" 82#define XATTR_SELINUX_SUFFIX "selinux"
83#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX 83#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
84 84
85#define NUM_SEL_MNT_OPTS 4
86
85extern unsigned int policydb_loaded_version; 87extern unsigned int policydb_loaded_version;
86extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); 88extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
87extern int selinux_compat_net; 89extern int selinux_compat_net;
@@ -321,8 +323,8 @@ enum {
321 Opt_error = -1, 323 Opt_error = -1,
322 Opt_context = 1, 324 Opt_context = 1,
323 Opt_fscontext = 2, 325 Opt_fscontext = 2,
324 Opt_defcontext = 4, 326 Opt_defcontext = 3,
325 Opt_rootcontext = 8, 327 Opt_rootcontext = 4,
326}; 328};
327 329
328static match_table_t tokens = { 330static match_table_t tokens = {
@@ -366,150 +368,317 @@ static int may_context_mount_inode_relabel(u32 sid,
366 return rc; 368 return rc;
367} 369}
368 370
369static int try_context_mount(struct super_block *sb, void *data) 371static int sb_finish_set_opts(struct super_block *sb)
370{ 372{
371 char *context = NULL, *defcontext = NULL;
372 char *fscontext = NULL, *rootcontext = NULL;
373 const char *name;
374 u32 sid;
375 int alloc = 0, rc = 0, seen = 0;
376 struct task_security_struct *tsec = current->security;
377 struct superblock_security_struct *sbsec = sb->s_security; 373 struct superblock_security_struct *sbsec = sb->s_security;
374 struct dentry *root = sb->s_root;
375 struct inode *root_inode = root->d_inode;
376 int rc = 0;
378 377
379 if (!data) 378 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
380 goto out; 379 /* Make sure that the xattr handler exists and that no
380 error other than -ENODATA is returned by getxattr on
381 the root directory. -ENODATA is ok, as this may be
382 the first boot of the SELinux kernel before we have
383 assigned xattr values to the filesystem. */
384 if (!root_inode->i_op->getxattr) {
385 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
386 "xattr support\n", sb->s_id, sb->s_type->name);
387 rc = -EOPNOTSUPP;
388 goto out;
389 }
390 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
391 if (rc < 0 && rc != -ENODATA) {
392 if (rc == -EOPNOTSUPP)
393 printk(KERN_WARNING "SELinux: (dev %s, type "
394 "%s) has no security xattr handler\n",
395 sb->s_id, sb->s_type->name);
396 else
397 printk(KERN_WARNING "SELinux: (dev %s, type "
398 "%s) getxattr errno %d\n", sb->s_id,
399 sb->s_type->name, -rc);
400 goto out;
401 }
402 }
381 403
382 name = sb->s_type->name; 404 sbsec->initialized = 1;
383 405
384 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) { 406 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
407 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
408 sb->s_id, sb->s_type->name);
409 else
410 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
411 sb->s_id, sb->s_type->name,
412 labeling_behaviors[sbsec->behavior-1]);
385 413
386 /* NFS we understand. */ 414 /* Initialize the root inode. */
387 if (!strcmp(name, "nfs")) { 415 rc = inode_doinit_with_dentry(root_inode, root);
388 struct nfs_mount_data *d = data;
389 416
390 if (d->version < NFS_MOUNT_VERSION) 417 /* Initialize any other inodes associated with the superblock, e.g.
391 goto out; 418 inodes created prior to initial policy load or inodes created
419 during get_sb by a pseudo filesystem that directly
420 populates itself. */
421 spin_lock(&sbsec->isec_lock);
422next_inode:
423 if (!list_empty(&sbsec->isec_head)) {
424 struct inode_security_struct *isec =
425 list_entry(sbsec->isec_head.next,
426 struct inode_security_struct, list);
427 struct inode *inode = isec->inode;
428 spin_unlock(&sbsec->isec_lock);
429 inode = igrab(inode);
430 if (inode) {
431 if (!IS_PRIVATE(inode))
432 inode_doinit(inode);
433 iput(inode);
434 }
435 spin_lock(&sbsec->isec_lock);
436 list_del_init(&isec->list);
437 goto next_inode;
438 }
439 spin_unlock(&sbsec->isec_lock);
440out:
441 return rc;
442}
392 443
393 if (d->context[0]) { 444/*
394 context = d->context; 445 * This function should allow an FS to ask what it's mount security
395 seen |= Opt_context; 446 * options were so it can use those later for submounts, displaying
396 } 447 * mount options, or whatever.
397 } else 448 */
398 goto out; 449static int selinux_get_mnt_opts(const struct super_block *sb,
450 char ***mount_options, int **mnt_opts_flags,
451 int *num_opts)
452{
453 int rc = 0, i;
454 struct superblock_security_struct *sbsec = sb->s_security;
455 char *context = NULL;
456 u32 len;
457 char tmp;
399 458
400 } else { 459 *num_opts = 0;
401 /* Standard string-based options. */ 460 *mount_options = NULL;
402 char *p, *options = data; 461 *mnt_opts_flags = NULL;
403 462
404 while ((p = strsep(&options, "|")) != NULL) { 463 if (!sbsec->initialized)
405 int token; 464 return -EINVAL;
406 substring_t args[MAX_OPT_ARGS];
407 465
408 if (!*p) 466 if (!ss_initialized)
409 continue; 467 return -EINVAL;
410 468
411 token = match_token(p, tokens, args); 469 /*
470 * if we ever use sbsec flags for anything other than tracking mount
471 * settings this is going to need a mask
472 */
473 tmp = sbsec->flags;
474 /* count the number of mount options for this sb */
475 for (i = 0; i < 8; i++) {
476 if (tmp & 0x01)
477 (*num_opts)++;
478 tmp >>= 1;
479 }
412 480
413 switch (token) { 481 *mount_options = kcalloc(*num_opts, sizeof(char *), GFP_ATOMIC);
414 case Opt_context: 482 if (!*mount_options) {
415 if (seen & (Opt_context|Opt_defcontext)) { 483 rc = -ENOMEM;
416 rc = -EINVAL; 484 goto out_free;
417 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); 485 }
418 goto out_free;
419 }
420 context = match_strdup(&args[0]);
421 if (!context) {
422 rc = -ENOMEM;
423 goto out_free;
424 }
425 if (!alloc)
426 alloc = 1;
427 seen |= Opt_context;
428 break;
429 486
430 case Opt_fscontext: 487 *mnt_opts_flags = kcalloc(*num_opts, sizeof(int), GFP_ATOMIC);
431 if (seen & Opt_fscontext) { 488 if (!*mnt_opts_flags) {
432 rc = -EINVAL; 489 rc = -ENOMEM;
433 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); 490 goto out_free;
434 goto out_free; 491 }
435 }
436 fscontext = match_strdup(&args[0]);
437 if (!fscontext) {
438 rc = -ENOMEM;
439 goto out_free;
440 }
441 if (!alloc)
442 alloc = 1;
443 seen |= Opt_fscontext;
444 break;
445 492
446 case Opt_rootcontext: 493 i = 0;
447 if (seen & Opt_rootcontext) { 494 if (sbsec->flags & FSCONTEXT_MNT) {
448 rc = -EINVAL; 495 rc = security_sid_to_context(sbsec->sid, &context, &len);
449 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); 496 if (rc)
450 goto out_free; 497 goto out_free;
451 } 498 (*mount_options)[i] = context;
452 rootcontext = match_strdup(&args[0]); 499 (*mnt_opts_flags)[i++] = FSCONTEXT_MNT;
453 if (!rootcontext) { 500 }
454 rc = -ENOMEM; 501 if (sbsec->flags & CONTEXT_MNT) {
455 goto out_free; 502 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
456 } 503 if (rc)
457 if (!alloc) 504 goto out_free;
458 alloc = 1; 505 (*mount_options)[i] = context;
459 seen |= Opt_rootcontext; 506 (*mnt_opts_flags)[i++] = CONTEXT_MNT;
460 break; 507 }
508 if (sbsec->flags & DEFCONTEXT_MNT) {
509 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
510 if (rc)
511 goto out_free;
512 (*mount_options)[i] = context;
513 (*mnt_opts_flags)[i++] = DEFCONTEXT_MNT;
514 }
515 if (sbsec->flags & ROOTCONTEXT_MNT) {
516 struct inode *root = sbsec->sb->s_root->d_inode;
517 struct inode_security_struct *isec = root->i_security;
461 518
462 case Opt_defcontext: 519 rc = security_sid_to_context(isec->sid, &context, &len);
463 if (sbsec->behavior != SECURITY_FS_USE_XATTR) { 520 if (rc)
464 rc = -EINVAL; 521 goto out_free;
465 printk(KERN_WARNING "SELinux: " 522 (*mount_options)[i] = context;
466 "defcontext option is invalid " 523 (*mnt_opts_flags)[i++] = ROOTCONTEXT_MNT;
467 "for this filesystem type\n"); 524 }
468 goto out_free;
469 }
470 if (seen & (Opt_context|Opt_defcontext)) {
471 rc = -EINVAL;
472 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
473 goto out_free;
474 }
475 defcontext = match_strdup(&args[0]);
476 if (!defcontext) {
477 rc = -ENOMEM;
478 goto out_free;
479 }
480 if (!alloc)
481 alloc = 1;
482 seen |= Opt_defcontext;
483 break;
484 525
485 default: 526 BUG_ON(i != *num_opts);
486 rc = -EINVAL;
487 printk(KERN_WARNING "SELinux: unknown mount "
488 "option\n");
489 goto out_free;
490 527
491 } 528 return 0;
492 } 529
493 } 530out_free:
531 /* don't leak context string if security_sid_to_context had an error */
532 if (*mount_options && i)
533 for (; i > 0; i--)
534 kfree((*mount_options)[i-1]);
535 kfree(*mount_options);
536 *mount_options = NULL;
537 kfree(*mnt_opts_flags);
538 *mnt_opts_flags = NULL;
539 *num_opts = 0;
540 return rc;
541}
542
543static int bad_option(struct superblock_security_struct *sbsec, char flag,
544 u32 old_sid, u32 new_sid)
545{
546 /* check if the old mount command had the same options */
547 if (sbsec->initialized)
548 if (!(sbsec->flags & flag) ||
549 (old_sid != new_sid))
550 return 1;
551
552 /* check if we were passed the same options twice,
553 * aka someone passed context=a,context=b
554 */
555 if (!sbsec->initialized)
556 if (sbsec->flags & flag)
557 return 1;
558 return 0;
559}
560/*
561 * Allow filesystems with binary mount data to explicitly set mount point
562 * labeling information.
563 */
564int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
565 int *flags, int num_opts)
566{
567 int rc = 0, i;
568 struct task_security_struct *tsec = current->security;
569 struct superblock_security_struct *sbsec = sb->s_security;
570 const char *name = sb->s_type->name;
571 struct inode *inode = sbsec->sb->s_root->d_inode;
572 struct inode_security_struct *root_isec = inode->i_security;
573 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
574 u32 defcontext_sid = 0;
494 575
495 if (!seen) 576 mutex_lock(&sbsec->lock);
577
578 if (!ss_initialized) {
579 if (!num_opts) {
580 /* Defer initialization until selinux_complete_init,
581 after the initial policy is loaded and the security
582 server is ready to handle calls. */
583 spin_lock(&sb_security_lock);
584 if (list_empty(&sbsec->list))
585 list_add(&sbsec->list, &superblock_security_head);
586 spin_unlock(&sb_security_lock);
587 goto out;
588 }
589 rc = -EINVAL;
590 printk(KERN_WARNING "Unable to set superblock options before "
591 "the security server is initialized\n");
496 goto out; 592 goto out;
593 }
497 594
498 /* sets the context of the superblock for the fs being mounted. */ 595 /*
499 if (fscontext) { 596 * parse the mount options, check if they are valid sids.
500 rc = security_context_to_sid(fscontext, strlen(fscontext), &sid); 597 * also check if someone is trying to mount the same sb more
598 * than once with different security options.
599 */
600 for (i = 0; i < num_opts; i++) {
601 u32 sid;
602 rc = security_context_to_sid(mount_options[i],
603 strlen(mount_options[i]), &sid);
501 if (rc) { 604 if (rc) {
502 printk(KERN_WARNING "SELinux: security_context_to_sid" 605 printk(KERN_WARNING "SELinux: security_context_to_sid"
503 "(%s) failed for (dev %s, type %s) errno=%d\n", 606 "(%s) failed for (dev %s, type %s) errno=%d\n",
504 fscontext, sb->s_id, name, rc); 607 mount_options[i], sb->s_id, name, rc);
505 goto out_free; 608 goto out;
609 }
610 switch (flags[i]) {
611 case FSCONTEXT_MNT:
612 fscontext_sid = sid;
613
614 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
615 fscontext_sid))
616 goto out_double_mount;
617
618 sbsec->flags |= FSCONTEXT_MNT;
619 break;
620 case CONTEXT_MNT:
621 context_sid = sid;
622
623 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
624 context_sid))
625 goto out_double_mount;
626
627 sbsec->flags |= CONTEXT_MNT;
628 break;
629 case ROOTCONTEXT_MNT:
630 rootcontext_sid = sid;
631
632 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
633 rootcontext_sid))
634 goto out_double_mount;
635
636 sbsec->flags |= ROOTCONTEXT_MNT;
637
638 break;
639 case DEFCONTEXT_MNT:
640 defcontext_sid = sid;
641
642 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
643 defcontext_sid))
644 goto out_double_mount;
645
646 sbsec->flags |= DEFCONTEXT_MNT;
647
648 break;
649 default:
650 rc = -EINVAL;
651 goto out;
506 } 652 }
653 }
654
655 if (sbsec->initialized) {
656 /* previously mounted with options, but not on this attempt? */
657 if (sbsec->flags && !num_opts)
658 goto out_double_mount;
659 rc = 0;
660 goto out;
661 }
507 662
508 rc = may_context_mount_sb_relabel(sid, sbsec, tsec); 663 if (strcmp(sb->s_type->name, "proc") == 0)
664 sbsec->proc = 1;
665
666 /* Determine the labeling behavior to use for this filesystem type. */
667 rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
668 if (rc) {
669 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
670 __FUNCTION__, sb->s_type->name, rc);
671 goto out;
672 }
673
674 /* sets the context of the superblock for the fs being mounted. */
675 if (fscontext_sid) {
676
677 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec);
509 if (rc) 678 if (rc)
510 goto out_free; 679 goto out;
511 680
512 sbsec->sid = sid; 681 sbsec->sid = fscontext_sid;
513 } 682 }
514 683
515 /* 684 /*
@@ -517,182 +686,250 @@ static int try_context_mount(struct super_block *sb, void *data)
517 * sets the label used on all file below the mountpoint, and will set 686 * sets the label used on all file below the mountpoint, and will set
518 * the superblock context if not already set. 687 * the superblock context if not already set.
519 */ 688 */
520 if (context) { 689 if (context_sid) {
521 rc = security_context_to_sid(context, strlen(context), &sid); 690 if (!fscontext_sid) {
522 if (rc) { 691 rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec);
523 printk(KERN_WARNING "SELinux: security_context_to_sid"
524 "(%s) failed for (dev %s, type %s) errno=%d\n",
525 context, sb->s_id, name, rc);
526 goto out_free;
527 }
528
529 if (!fscontext) {
530 rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
531 if (rc) 692 if (rc)
532 goto out_free; 693 goto out;
533 sbsec->sid = sid; 694 sbsec->sid = context_sid;
534 } else { 695 } else {
535 rc = may_context_mount_inode_relabel(sid, sbsec, tsec); 696 rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec);
536 if (rc) 697 if (rc)
537 goto out_free; 698 goto out;
538 } 699 }
539 sbsec->mntpoint_sid = sid; 700 if (!rootcontext_sid)
701 rootcontext_sid = context_sid;
540 702
703 sbsec->mntpoint_sid = context_sid;
541 sbsec->behavior = SECURITY_FS_USE_MNTPOINT; 704 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
542 } 705 }
543 706
544 if (rootcontext) { 707 if (rootcontext_sid) {
545 struct inode *inode = sb->s_root->d_inode; 708 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec);
546 struct inode_security_struct *isec = inode->i_security;
547 rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid);
548 if (rc) {
549 printk(KERN_WARNING "SELinux: security_context_to_sid"
550 "(%s) failed for (dev %s, type %s) errno=%d\n",
551 rootcontext, sb->s_id, name, rc);
552 goto out_free;
553 }
554
555 rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
556 if (rc) 709 if (rc)
557 goto out_free; 710 goto out;
558 711
559 isec->sid = sid; 712 root_isec->sid = rootcontext_sid;
560 isec->initialized = 1; 713 root_isec->initialized = 1;
561 } 714 }
562 715
563 if (defcontext) { 716 if (defcontext_sid) {
564 rc = security_context_to_sid(defcontext, strlen(defcontext), &sid); 717 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
565 if (rc) { 718 rc = -EINVAL;
566 printk(KERN_WARNING "SELinux: security_context_to_sid" 719 printk(KERN_WARNING "SELinux: defcontext option is "
567 "(%s) failed for (dev %s, type %s) errno=%d\n", 720 "invalid for this filesystem type\n");
568 defcontext, sb->s_id, name, rc); 721 goto out;
569 goto out_free;
570 } 722 }
571 723
572 if (sid == sbsec->def_sid) 724 if (defcontext_sid != sbsec->def_sid) {
573 goto out_free; 725 rc = may_context_mount_inode_relabel(defcontext_sid,
574 726 sbsec, tsec);
575 rc = may_context_mount_inode_relabel(sid, sbsec, tsec); 727 if (rc)
576 if (rc) 728 goto out;
577 goto out_free; 729 }
578 730
579 sbsec->def_sid = sid; 731 sbsec->def_sid = defcontext_sid;
580 } 732 }
581 733
582out_free: 734 rc = sb_finish_set_opts(sb);
583 if (alloc) {
584 kfree(context);
585 kfree(defcontext);
586 kfree(fscontext);
587 kfree(rootcontext);
588 }
589out: 735out:
736 mutex_unlock(&sbsec->lock);
590 return rc; 737 return rc;
738out_double_mount:
739 rc = -EINVAL;
740 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
741 "security settings for (dev %s, type %s)\n", sb->s_id, name);
742 goto out;
591} 743}
592 744
593static int superblock_doinit(struct super_block *sb, void *data) 745static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
746 struct super_block *newsb)
594{ 747{
595 struct superblock_security_struct *sbsec = sb->s_security; 748 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
596 struct dentry *root = sb->s_root; 749 struct superblock_security_struct *newsbsec = newsb->s_security;
597 struct inode *inode = root->d_inode;
598 int rc = 0;
599 750
600 mutex_lock(&sbsec->lock); 751 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
601 if (sbsec->initialized) 752 int set_context = (oldsbsec->flags & CONTEXT_MNT);
602 goto out; 753 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
603 754
604 if (!ss_initialized) { 755 /* we can't error, we can't save the info, this shouldn't get called
605 /* Defer initialization until selinux_complete_init, 756 * this early in the boot process. */
606 after the initial policy is loaded and the security 757 BUG_ON(!ss_initialized);
607 server is ready to handle calls. */ 758
608 spin_lock(&sb_security_lock); 759 /* this might go away sometime down the line if there is a new user
609 if (list_empty(&sbsec->list)) 760 * of clone, but for now, nfs better not get here... */
610 list_add(&sbsec->list, &superblock_security_head); 761 BUG_ON(newsbsec->initialized);
611 spin_unlock(&sb_security_lock); 762
612 goto out; 763 /* how can we clone if the old one wasn't set up?? */
764 BUG_ON(!oldsbsec->initialized);
765
766 mutex_lock(&newsbsec->lock);
767
768 newsbsec->flags = oldsbsec->flags;
769
770 newsbsec->sid = oldsbsec->sid;
771 newsbsec->def_sid = oldsbsec->def_sid;
772 newsbsec->behavior = oldsbsec->behavior;
773
774 if (set_context) {
775 u32 sid = oldsbsec->mntpoint_sid;
776
777 if (!set_fscontext)
778 newsbsec->sid = sid;
779 if (!set_rootcontext) {
780 struct inode *newinode = newsb->s_root->d_inode;
781 struct inode_security_struct *newisec = newinode->i_security;
782 newisec->sid = sid;
783 }
784 newsbsec->mntpoint_sid = sid;
613 } 785 }
786 if (set_rootcontext) {
787 const struct inode *oldinode = oldsb->s_root->d_inode;
788 const struct inode_security_struct *oldisec = oldinode->i_security;
789 struct inode *newinode = newsb->s_root->d_inode;
790 struct inode_security_struct *newisec = newinode->i_security;
614 791
615 /* Determine the labeling behavior to use for this filesystem type. */ 792 newisec->sid = oldisec->sid;
616 rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
617 if (rc) {
618 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
619 __FUNCTION__, sb->s_type->name, rc);
620 goto out;
621 } 793 }
622 794
623 rc = try_context_mount(sb, data); 795 sb_finish_set_opts(newsb);
624 if (rc) 796 mutex_unlock(&newsbsec->lock);
797}
798
799/*
800 * string mount options parsing and call set the sbsec
801 */
802static int superblock_doinit(struct super_block *sb, void *data)
803{
804 char *context = NULL, *defcontext = NULL;
805 char *fscontext = NULL, *rootcontext = NULL;
806 int rc = 0;
807 char *p, *options = data;
808 /* selinux only know about a fixed number of mount options */
809 char *mnt_opts[NUM_SEL_MNT_OPTS];
810 int mnt_opts_flags[NUM_SEL_MNT_OPTS], num_mnt_opts = 0;
811
812 if (!data)
625 goto out; 813 goto out;
626 814
627 if (sbsec->behavior == SECURITY_FS_USE_XATTR) { 815 /* with the nfs patch this will become a goto out; */
628 /* Make sure that the xattr handler exists and that no 816 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) {
629 error other than -ENODATA is returned by getxattr on 817 const char *name = sb->s_type->name;
630 the root directory. -ENODATA is ok, as this may be 818 /* NFS we understand. */
631 the first boot of the SELinux kernel before we have 819 if (!strcmp(name, "nfs")) {
632 assigned xattr values to the filesystem. */ 820 struct nfs_mount_data *d = data;
633 if (!inode->i_op->getxattr) { 821
634 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no " 822 if (d->version != NFS_MOUNT_VERSION)
635 "xattr support\n", sb->s_id, sb->s_type->name); 823 goto out;
636 rc = -EOPNOTSUPP; 824
637 goto out; 825 if (d->context[0]) {
638 } 826 context = kstrdup(d->context, GFP_KERNEL);
639 rc = inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); 827 if (!context) {
640 if (rc < 0 && rc != -ENODATA) { 828 rc = -ENOMEM;
641 if (rc == -EOPNOTSUPP) 829 goto out;
642 printk(KERN_WARNING "SELinux: (dev %s, type " 830 }
643 "%s) has no security xattr handler\n", 831 }
644 sb->s_id, sb->s_type->name); 832 goto build_flags;
645 else 833 } else
646 printk(KERN_WARNING "SELinux: (dev %s, type "
647 "%s) getxattr errno %d\n", sb->s_id,
648 sb->s_type->name, -rc);
649 goto out; 834 goto out;
650 }
651 } 835 }
652 836
653 if (strcmp(sb->s_type->name, "proc") == 0) 837 /* Standard string-based options. */
654 sbsec->proc = 1; 838 while ((p = strsep(&options, "|")) != NULL) {
839 int token;
840 substring_t args[MAX_OPT_ARGS];
655 841
656 sbsec->initialized = 1; 842 if (!*p)
843 continue;
657 844
658 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) { 845 token = match_token(p, tokens, args);
659 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
660 sb->s_id, sb->s_type->name);
661 }
662 else {
663 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
664 sb->s_id, sb->s_type->name,
665 labeling_behaviors[sbsec->behavior-1]);
666 }
667 846
668 /* Initialize the root inode. */ 847 switch (token) {
669 rc = inode_doinit_with_dentry(sb->s_root->d_inode, sb->s_root); 848 case Opt_context:
849 if (context || defcontext) {
850 rc = -EINVAL;
851 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
852 goto out_err;
853 }
854 context = match_strdup(&args[0]);
855 if (!context) {
856 rc = -ENOMEM;
857 goto out_err;
858 }
859 break;
860
861 case Opt_fscontext:
862 if (fscontext) {
863 rc = -EINVAL;
864 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
865 goto out_err;
866 }
867 fscontext = match_strdup(&args[0]);
868 if (!fscontext) {
869 rc = -ENOMEM;
870 goto out_err;
871 }
872 break;
873
874 case Opt_rootcontext:
875 if (rootcontext) {
876 rc = -EINVAL;
877 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
878 goto out_err;
879 }
880 rootcontext = match_strdup(&args[0]);
881 if (!rootcontext) {
882 rc = -ENOMEM;
883 goto out_err;
884 }
885 break;
886
887 case Opt_defcontext:
888 if (context || defcontext) {
889 rc = -EINVAL;
890 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
891 goto out_err;
892 }
893 defcontext = match_strdup(&args[0]);
894 if (!defcontext) {
895 rc = -ENOMEM;
896 goto out_err;
897 }
898 break;
899
900 default:
901 rc = -EINVAL;
902 printk(KERN_WARNING "SELinux: unknown mount option\n");
903 goto out_err;
670 904
671 /* Initialize any other inodes associated with the superblock, e.g.
672 inodes created prior to initial policy load or inodes created
673 during get_sb by a pseudo filesystem that directly
674 populates itself. */
675 spin_lock(&sbsec->isec_lock);
676next_inode:
677 if (!list_empty(&sbsec->isec_head)) {
678 struct inode_security_struct *isec =
679 list_entry(sbsec->isec_head.next,
680 struct inode_security_struct, list);
681 struct inode *inode = isec->inode;
682 spin_unlock(&sbsec->isec_lock);
683 inode = igrab(inode);
684 if (inode) {
685 if (!IS_PRIVATE (inode))
686 inode_doinit(inode);
687 iput(inode);
688 } 905 }
689 spin_lock(&sbsec->isec_lock);
690 list_del_init(&isec->list);
691 goto next_inode;
692 } 906 }
693 spin_unlock(&sbsec->isec_lock); 907
908build_flags:
909 if (fscontext) {
910 mnt_opts[num_mnt_opts] = fscontext;
911 mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
912 }
913 if (context) {
914 mnt_opts[num_mnt_opts] = context;
915 mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
916 }
917 if (rootcontext) {
918 mnt_opts[num_mnt_opts] = rootcontext;
919 mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
920 }
921 if (defcontext) {
922 mnt_opts[num_mnt_opts] = defcontext;
923 mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
924 }
925
694out: 926out:
695 mutex_unlock(&sbsec->lock); 927 rc = selinux_set_mnt_opts(sb, mnt_opts, mnt_opts_flags, num_mnt_opts);
928out_err:
929 kfree(context);
930 kfree(defcontext);
931 kfree(fscontext);
932 kfree(rootcontext);
696 return rc; 933 return rc;
697} 934}
698 935
@@ -4800,6 +5037,9 @@ static struct security_operations selinux_ops = {
4800 .sb_statfs = selinux_sb_statfs, 5037 .sb_statfs = selinux_sb_statfs,
4801 .sb_mount = selinux_mount, 5038 .sb_mount = selinux_mount,
4802 .sb_umount = selinux_umount, 5039 .sb_umount = selinux_umount,
5040 .sb_get_mnt_opts = selinux_get_mnt_opts,
5041 .sb_set_mnt_opts = selinux_set_mnt_opts,
5042 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
4803 5043
4804 .inode_alloc_security = selinux_inode_alloc_security, 5044 .inode_alloc_security = selinux_inode_alloc_security,
4805 .inode_free_security = selinux_inode_free_security, 5045 .inode_free_security = selinux_inode_free_security,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 642a9fd319ad..4138a80f8e27 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -65,6 +65,7 @@ struct superblock_security_struct {
65 u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ 65 u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
66 unsigned int behavior; /* labeling behavior */ 66 unsigned int behavior; /* labeling behavior */
67 unsigned char initialized; /* initialization flag */ 67 unsigned char initialized; /* initialization flag */
68 unsigned char flags; /* which mount options were specified */
68 unsigned char proc; /* proc fs */ 69 unsigned char proc; /* proc fs */
69 struct mutex lock; 70 struct mutex lock;
70 struct list_head isec_head; 71 struct list_head isec_head;