From: Christopher Faulet Date: Mon, 27 Jul 2026 10:15:11 +0000 (+0200) Subject: BUG/MINOR: http-rules: fix release of a failed "set-cookie-fmt" redirect rule X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=0e53d875c78550b91a645d40f28af978af864d69;p=thirdparty%2Fhaproxy.git BUG/MINOR: http-rules: fix release of a failed "set-cookie-fmt" redirect rule 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 member while 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. --- diff --git a/src/http_rules.c b/src/http_rules.c index ee4543083..05801b1f3 100644 --- a/src/http_rules.c +++ b/src/http_rules.c @@ -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: