]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: http-rules: fix release of a failed "set-cookie-fmt" redirect rule
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 27 Jul 2026 10:15:11 +0000 (12:15 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 28 Jul 2026 13:28:29 +0000 (15:28 +0200)
<redirect_rule.cookie> is a union holding either an ist (set-cookie,
clear-cookie) or a log-format expression (set-cookie-fmt), and
http_free_redirect_rule() picks the member to release from the
REDIRECT_FLAG_COOKIE_FMT flag:

if ((rdr->flags & REDIRECT_FLAG_COOKIE_FMT))
lf_expr_deinit(&rdr->cookie.fmt);
else
istfree(&rdr->cookie.str);

But http_parse_redirect_rule() accumulates the flags in a local variable and
only assigns them with "rule->flags = flags" at the very end, once
everything succeeded. So when the log-format string of a "set-cookie-fmt"
fails to parse, the "goto err" runs http_free_redirect_rule() on a rule
whose ->flags is still 0, and istfree() is called on the <str> member while
<fmt> is the live one, leading the process to crash.

Let's init the rule members (code, type and flags) as soon as possible, so
after the rule allocation. And REDIRECT_FLAG_COOKIE_FMT flag is not set
directly on the rule's flags, before the log-format string parsing.

This only happens while parsing an invalid configuration, hence no security
impact, but a configuration checker must report errors rather than abort.

This should be backported to all versions having "set-cookie-fmt", so 2.9 and
above.

src/http_rules.c

index ee4543083eb980d6acd6e9b769a7f666118e1be3..05801b1f30ec2ba3743bda767a7fe9ddfaade9e1 100644 (file)
@@ -456,6 +456,10 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
        if (!rule)
                goto out_of_memory;
        rule->cond = cond;
+       rule->type = type;
+       rule->code = code;
+       rule->flags = flags;
+       LIST_INIT(&rule->list);
        lf_expr_init(&rule->rdr_fmt);
 
        if (!use_fmt) {
@@ -478,7 +482,7 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
                        cap |= (dir ? SMP_VAL_FE_HRS_HDR : SMP_VAL_FE_HRQ_HDR);
                if (curproxy->cap & PR_CAP_BE)
                        cap |= (dir ? SMP_VAL_BE_HRS_HDR : SMP_VAL_BE_HRQ_HDR);
-               if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
+               if (!(rule->type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
                        if (!parse_logformat_string(destination, curproxy, &rule->rdr_fmt, LOG_OPT_HTTP, cap, errmsg)) {
                                goto err;
                        }
@@ -500,6 +504,8 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
                else if (cookie_set == 2) { // set-cookie-fmt
                        int cap = 0;
 
+                       rule->flags |= REDIRECT_FLAG_COOKIE_FMT;
+
                        lf_expr_init(&rule->cookie.fmt);
                        curproxy->conf.args.ctx = ARGC_RDR;
                        if (curproxy->cap & PR_CAP_FE)
@@ -512,8 +518,6 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
                        if (!parse_logformat_string(trash.area, curproxy, &rule->cookie.fmt, LOG_OPT_HTTP, cap, errmsg)) {
                                goto err;
                        }
-
-                       flags |= REDIRECT_FLAG_COOKIE_FMT;
                }
                else { // clear-cookie
                        rule->cookie.str = istalloc(cookie_len+20);
@@ -523,10 +527,7 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
                        istcat(&rule->cookie.str, ist2("; path=/; Max-Age=0;", 20), cookie_len+21);
                }
        }
-       rule->type = type;
-       rule->code = code;
-       rule->flags = flags;
-       LIST_INIT(&rule->list);
+
        return rule;
 
  missing_arg: