diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2018-12-14 21:56:23 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2018-12-21 11:49:54 -0500 |
commit | 99dbbb593fe6b39153c15ea9b9c63ea911864cf2 (patch) | |
tree | 9e86c597e17607426dec5639e5aca2c9a670c306 /security/selinux | |
parent | da3d76abb2e74c07b1cd620ee5e3b31227846c7c (diff) |
selinux: rewrite selinux_sb_eat_lsm_opts()
make it use selinux_add_opt() and avoid separate copies - gather
non-LSM options by memmove() in place
Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'security/selinux')
-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) |