summaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-12-14 21:56:23 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2018-12-21 11:49:54 -0500
commit99dbbb593fe6b39153c15ea9b9c63ea911864cf2 (patch)
tree9e86c597e17607426dec5639e5aca2c9a670c306 /security/selinux
parentda3d76abb2e74c07b1cd620ee5e3b31227846c7c (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.c146
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
2609static inline int match_prefix(char *prefix, int plen, char *option, int olen) 2609static 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
2617static 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
2626static 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
2637static 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
2658static int selinux_sb_copy_data(char *orig, char *copy) 2624static 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 }
2696out: 2672 *to = '\0';
2697 return rc; 2673 return 0;
2698}
2699
2700static 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
2714static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) 2676static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)