diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/dummy.c | 26 | ||||
-rw-r--r-- | security/security.c | 20 | ||||
-rw-r--r-- | security/selinux/hooks.c | 748 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 1 |
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 | ||
248 | static 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 | |||
257 | static 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 | |||
265 | static void dummy_sb_clone_mnt_opts(const struct super_block *oldsb, | ||
266 | struct super_block *newsb) | ||
267 | { | ||
268 | return; | ||
269 | } | ||
270 | |||
248 | static int dummy_inode_alloc_security (struct inode *inode) | 271 | static 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 | ||
311 | int 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 | |||
318 | int 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 | |||
325 | void 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 | |||
311 | int security_inode_alloc(struct inode *inode) | 331 | int 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 | |||
85 | extern unsigned int policydb_loaded_version; | 87 | extern unsigned int policydb_loaded_version; |
86 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); | 88 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); |
87 | extern int selinux_compat_net; | 89 | extern 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 | ||
328 | static match_table_t tokens = { | 330 | static 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 | ||
369 | static int try_context_mount(struct super_block *sb, void *data) | 371 | static 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); | ||
422 | next_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); | ||
440 | out: | ||
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; | 449 | static 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 | } | 530 | out_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 | |||
543 | static 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 | */ | ||
564 | int 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 | ||
582 | out_free: | 734 | rc = sb_finish_set_opts(sb); |
583 | if (alloc) { | ||
584 | kfree(context); | ||
585 | kfree(defcontext); | ||
586 | kfree(fscontext); | ||
587 | kfree(rootcontext); | ||
588 | } | ||
589 | out: | 735 | out: |
736 | mutex_unlock(&sbsec->lock); | ||
590 | return rc; | 737 | return rc; |
738 | out_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 | ||
593 | static int superblock_doinit(struct super_block *sb, void *data) | 745 | static 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 | */ | ||
802 | static 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); | ||
676 | next_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 | |
908 | build_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 | |||
694 | out: | 926 | out: |
695 | mutex_unlock(&sbsec->lock); | 927 | rc = selinux_set_mnt_opts(sb, mnt_opts, mnt_opts_flags, num_mnt_opts); |
928 | out_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; |