]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: arg: ensure that we properly unlink unresolved arguments on error
authorWilly Tarreau <w@1wt.eu>
Wed, 12 Apr 2017 20:32:04 +0000 (22:32 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 13 Apr 2017 10:20:52 +0000 (12:20 +0200)
If make_arg_list() fails to process an argument after having queued an
unresolvable one, it frees the allocated argument list but doesn't remove
the referenced args from the arg list. This causes a use after free or a
double free if the same location was reused, during the deinit phase upon
exit after reporting the error.

Since it's not easy to properly unlinked all elements, we only release the
args block if none of them was queued in the list.

src/arg.c

index ca914faa9ca4fb9208cb1c5d3cf521e020cb7a38..52977b7180f728f6feff76e6f0740c66dee92f87 100644 (file)
--- a/src/arg.c
+++ b/src/arg.c
@@ -104,6 +104,7 @@ int make_arg_list(const char *in, int len, uint64_t mask, struct arg **argp,
        char *word = NULL;
        const char *ptr_err = NULL;
        int min_arg;
+       struct arg_list *new_al = al;
 
        *argp = NULL;
 
@@ -165,7 +166,7 @@ int make_arg_list(const char *in, int len, uint64_t mask, struct arg **argp,
                         * parsing then resolved later.
                         */
                        arg->unresolved = 1;
-                       arg_list_add(al, arg, pos);
+                       new_al = arg_list_add(al, arg, pos);
 
                        /* fall through */
                case ARGT_STR:
@@ -282,7 +283,12 @@ int make_arg_list(const char *in, int len, uint64_t mask, struct arg **argp,
 
  err:
        free(word);
-       free(*argp);
+       if (new_al == al) {
+               /* only free the arg area if we have not queued unresolved args
+                * still pointing to it.
+                */
+               free(*argp);
+       }
        *argp = NULL;
        if (err_arg)
                *err_arg = pos;