diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/selinux/hooks.c | 146 |
1 files changed, 54 insertions, 92 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9b350070ed9e..5336d6671c5c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -2606,109 +2606,71 @@ static void selinux_sb_free_security(struct super_block *sb) | |||
| 2606 | superblock_free_security(sb); | 2606 | superblock_free_security(sb); |
| 2607 | } | 2607 | } |
| 2608 | 2608 | ||
| 2609 | static inline int match_prefix(char *prefix, int plen, char *option, int olen) | 2609 | static inline int opt_len(const char *s) |
| 2610 | { | 2610 | { |
| 2611 | if (plen > olen) | 2611 | bool open_quote = false; |
| 2612 | return 0; | 2612 | int len; |
| 2613 | 2613 | char c; | |
| 2614 | return !memcmp(prefix, option, plen); | ||
| 2615 | } | ||
| 2616 | |||
| 2617 | static inline int selinux_option(char *option, int len) | ||
| 2618 | { | ||
| 2619 | return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || | ||
| 2620 | match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || | ||
| 2621 | match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || | ||
| 2622 | match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) || | ||
| 2623 | match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len)); | ||
| 2624 | } | ||
| 2625 | |||
| 2626 | static inline void take_option(char **to, char *from, int *first, int len) | ||
| 2627 | { | ||
| 2628 | if (!*first) { | ||
| 2629 | **to = ','; | ||
| 2630 | *to += 1; | ||
| 2631 | } else | ||
| 2632 | *first = 0; | ||
| 2633 | memcpy(*to, from, len); | ||
| 2634 | *to += len; | ||
| 2635 | } | ||
| 2636 | |||
| 2637 | static inline void take_selinux_option(char **to, char *from, int *first, | ||
| 2638 | int len) | ||
| 2639 | { | ||
| 2640 | int current_size = 0; | ||
| 2641 | |||
| 2642 | if (!*first) { | ||
| 2643 | **to = '|'; | ||
| 2644 | *to += 1; | ||
| 2645 | } else | ||
| 2646 | *first = 0; | ||
| 2647 | 2614 | ||
| 2648 | while (current_size < len) { | 2615 | for (len = 0; (c = s[len]) != '\0'; len++) { |
| 2649 | if (*from != '"') { | 2616 | if (c == '"') |
| 2650 | **to = *from; | 2617 | open_quote = !open_quote; |
| 2651 | *to += 1; | 2618 | if (c == ',' && !open_quote) |
| 2652 | } | 2619 | break; |
| 2653 | from += 1; | ||
| 2654 | current_size += 1; | ||
| 2655 | } | 2620 | } |
| 2621 | return len; | ||
| 2656 | } | 2622 | } |
| 2657 | 2623 | ||
| 2658 | static int selinux_sb_copy_data(char *orig, char *copy) | 2624 | static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) |
| 2659 | { | 2625 | { |
| 2660 | int fnosec, fsec, rc = 0; | 2626 | char *from = options; |
| 2661 | char *in_save, *in_curr, *in_end; | 2627 | char *to = options; |
| 2662 | char *sec_curr, *nosec_save, *nosec; | 2628 | bool first = true; |
| 2663 | int open_quote = 0; | ||
| 2664 | 2629 | ||
| 2665 | in_curr = orig; | 2630 | while (1) { |
| 2666 | sec_curr = copy; | 2631 | int len = opt_len(from); |
| 2632 | int token, rc; | ||
| 2633 | char *arg = NULL; | ||
| 2667 | 2634 | ||
| 2668 | nosec = (char *)get_zeroed_page(GFP_KERNEL); | 2635 | token = match_opt_prefix(from, len, &arg); |
| 2669 | if (!nosec) { | ||
| 2670 | rc = -ENOMEM; | ||
| 2671 | goto out; | ||
| 2672 | } | ||
| 2673 | 2636 | ||
| 2674 | nosec_save = nosec; | 2637 | if (token != Opt_error) { |
| 2675 | fnosec = fsec = 1; | 2638 | char *p, *q; |
| 2676 | in_save = in_end = orig; | ||
| 2677 | 2639 | ||
| 2678 | do { | 2640 | /* strip quotes */ |
| 2679 | if (*in_end == '"') | 2641 | if (arg) { |
| 2680 | open_quote = !open_quote; | 2642 | for (p = q = arg; p < from + len; p++) { |
| 2681 | if ((*in_end == ',' && open_quote == 0) || | 2643 | char c = *p; |
| 2682 | *in_end == '\0') { | 2644 | if (c != '"') |
| 2683 | int len = in_end - in_curr; | 2645 | *q++ = c; |
| 2684 | 2646 | } | |
| 2685 | if (selinux_option(in_curr, len)) | 2647 | arg = kmemdup_nul(arg, q - arg, GFP_KERNEL); |
| 2686 | take_selinux_option(&sec_curr, in_curr, &fsec, len); | 2648 | } |
| 2687 | else | 2649 | rc = selinux_add_opt(token, arg, mnt_opts); |
| 2688 | take_option(&nosec, in_curr, &fnosec, len); | 2650 | if (unlikely(rc)) { |
| 2689 | 2651 | kfree(arg); | |
| 2690 | in_curr = in_end + 1; | 2652 | if (*mnt_opts) { |
| 2653 | selinux_free_mnt_opts(*mnt_opts); | ||
| 2654 | *mnt_opts = NULL; | ||
| 2655 | } | ||
| 2656 | return rc; | ||
| 2657 | } | ||
| 2658 | } else { | ||
| 2659 | if (!first) { // copy with preceding comma | ||
| 2660 | from--; | ||
| 2661 | len++; | ||
| 2662 | } | ||
| 2663 | if (to != from) | ||
| 2664 | memmove(to, from, len); | ||
| 2665 | to += len; | ||
| 2666 | first = false; | ||
| 2691 | } | 2667 | } |
| 2692 | } while (*in_end++); | 2668 | if (!from[len]) |
| 2693 | 2669 | break; | |
| 2694 | strcpy(in_save, nosec_save); | 2670 | from += len + 1; |
| 2695 | free_page((unsigned long)nosec_save); | 2671 | } |
| 2696 | out: | 2672 | *to = '\0'; |
| 2697 | return rc; | 2673 | return 0; |
| 2698 | } | ||
| 2699 | |||
| 2700 | static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) | ||
| 2701 | { | ||
| 2702 | char *s = (char *)get_zeroed_page(GFP_KERNEL); | ||
| 2703 | int err; | ||
| 2704 | |||
| 2705 | if (!s) | ||
| 2706 | return -ENOMEM; | ||
| 2707 | err = selinux_sb_copy_data(options, s); | ||
| 2708 | if (!err) | ||
| 2709 | err = selinux_parse_opts_str(s, mnt_opts); | ||
| 2710 | free_page((unsigned long)s); | ||
| 2711 | return err; | ||
| 2712 | } | 2674 | } |
| 2713 | 2675 | ||
| 2714 | static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) | 2676 | static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) |
