On Sun, Jan 29, 2017 at 2:14 PM, Felix Fietkau <[email protected]> wrote:
> When using musl libc glob() a very long string can cause glob() to fail,
> which leads to an out of memory error being raised by ash.
>
> This can happen easily if a very long quoted string contains *, even
> though no glob expansion should ever be performed on it (since it's
> quoted).
>
> Fix this by properly parsing control characters and escaping and only
> accept unquoted metacharacters. While we're at it, unify this check for
> libc and built-in glob expansion
>
> Signed-off-by: Felix Fietkau <[email protected]>
> ---
>  shell/ash.c | 61 
> ++++++++++++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 44 insertions(+), 17 deletions(-)
>
> diff --git a/shell/ash.c b/shell/ash.c
> index d8f41327b..642a2c727 100644
> --- a/shell/ash.c
> +++ b/shell/ash.c
> @@ -7159,6 +7159,47 @@ addfname(const char *name)
>         exparg.lastp = &sp->next;
>  }
>
> +static int hasmeta(struct strlist *str)
> +{
> +       static const char chars[] ALIGN1 = {
> +               '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
> +       };
> +       static const char qchars[] ALIGN1 = {
> +               CTLQUOTEMARK, CTLESC, 0
> +       };
> +       char *p;
> +
> +       /* Avoid glob() (and thus, stat() et al) for words like "echo" */
> +       for (p = str->text; p && *p; p = strpbrk(p + 1, chars)) {
> +               switch ((unsigned char) *p) {
> +               case CTLQUOTEMARK:
> +                       while (1) {
> +                               p = strpbrk(p + 1, qchars);
> +                               if (!p)
> +                                       return 0;
> +                               if (*p == CTLQUOTEMARK)
> +                                       break;
> +                               p++;
> +                       }
> +                       continue;
> +               case '\\':
> +               case CTLESC:
> +                       if (!p[1])
> +                               return 0;
> +
> +                       p++;
> +                       continue;
> +               case '*':
> +               case '?':
> +                       return 1;
> +               case '[':
> +                       return !!strchr(p + 1, ']');
> +               }
> +       }
> +
> +       return 0;
> +}

I plan to massage it into this - do you see any bugs?

static int
hasmeta(const char *p)
{
        static const char chars[] ALIGN1 = {
                '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
        };

        for (;;) {
                switch ((unsigned char) *p) {
                case '\0':
                        return 0;
                case CTLQUOTEMARK:
                        for (;;) {
                                p++;
                                if (*p == CTLQUOTEMARK)
                                        break;
                                if (*p == CTLESC)
                                        p++;
                                if (*p == '\0') /* huh? */
                                        return 0;
                        }
                        break;
                case '\\':
                case CTLESC:
                        p++;
                        if (*p == '\0')
                                return 0;
                        break;
                case '*':
                case '?':
                        return 1;
                case '[':
                        return strchr(p + 1, ']') != NULL;
                }
                p = strpbrk(p + 1, chars);
                if (!p)
                        break;
        }

        return 0;
}

Oh. What about unclosed "[" followed by metachars? "file[weird_name.*"
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to