mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-20 04:37:04 +00:00
BUG/MEDIUM: acl: don't free unresolved args in prune_acl_expr()
In case of error it's very difficult to properly unroll the list of unresolved args because the error can appear on any argument, and all of them share the same memory area, pointed to by one or multiple links from the global args list. The problem is that till now the arguments themselves were released and were not unlinked from the list, causing all forms of corruption in deinit() when quitting on the error path if an argument couldn't properly parse. A few attempts at trying to selectively spot the appropriate list entries to kill before releasing the shared area have only resulted in complicating the code and pushing the issue further. Here instead we use a simple conservative approach : prune_acl_expr() only tries to free the argument array if none of the arguments were unresolved, which means that none of them was added to the arg list. It's unclear what a better approach would be. We could imagine that args would point to their own location in the shared list but given that this extra cost and complexity would be added exclusively in order to cleanly release everything when we're exiting due to a config parse error, this seems quite overkill. This bug was noticed on 1.7 and likely affects 1.6 and 1.5, so the fix should be backported. It's not easy to reproduce it, as the reproducers randomly work depending on how memory is allocated. One way to do it is to use parsable and non-parsable patterns on an ACL making use of args. Big thanks to Stephan Zeisberg for reporting this problem with a working reproducer.
This commit is contained in:
parent
0622f02b5a
commit
145325e59d
@ -105,6 +105,7 @@ struct acl_keyword *find_acl_kw(const char *kw)
|
||||
static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
|
||||
{
|
||||
struct arg *arg;
|
||||
int unresolved = 0;
|
||||
|
||||
pattern_prune(&expr->pat);
|
||||
|
||||
@ -114,11 +115,12 @@ static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
|
||||
if (arg->type == ARGT_STR || arg->unresolved) {
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
unresolved |= arg->unresolved;
|
||||
arg->unresolved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (expr->smp->arg_p != empty_arg_list)
|
||||
if (expr->smp->arg_p != empty_arg_list && !unresolved)
|
||||
free(expr->smp->arg_p);
|
||||
return expr;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user