BUG/MINOR: pattern: pat_ref_set: fix UAF reported by coverity
memprintf() performs realloc and updates then the pointer to an output buffer,
where it has written the data. So free() is called on the previous buffer
address, if it was provided.
pat_ref_set_elt() uses memprintf() to write its error message as well as
pat_ref_set(). So, when we re-enter into the while loop the second time and
pat_ref_set_elt() has returned, the *err ptr (previous value of *merr) is
already freed by memprintf() from pat_ref_set_el().
'if (!found)' condition is false at this point, because we've found a node at
the first loop. So, the second memprintf(), in order to write error messages,
does again free(*err).
This should be backported in all stable versions.
(cherry picked from commit 4f2493f3551f8c344485cccf075c3b15f9825181)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit bf82f46ef01db0fc89a05b14721ca05d186f193b)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit d8655b0c1305d97bf7cab9f4c6c9900b37126c2f)
[wt: adapted ctx: it's a list not a tree in 2.8]
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/src/pattern.c b/src/pattern.c
index bcabd3e..87ebefa 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -1763,28 +1763,15 @@
{
struct pat_ref_elt *elt;
int found = 0;
- char *_merr;
- char **merr;
-
- if (err) {
- merr = &_merr;
- *merr = NULL;
- }
- else
- merr = NULL;
/* Look for pattern in the reference. */
list_for_each_entry(elt, &ref->head, list) {
if (strcmp(key, elt->pattern) == 0) {
- if (!pat_ref_set_elt(ref, elt, value, merr)) {
- if (err && merr) {
- if (!found) {
- *err = *merr;
- } else {
- memprintf(err, "%s, %s", *err, *merr);
- ha_free(merr);
- }
- }
+ char *tmp_err = NULL;
+
+ if (!pat_ref_set_elt(ref, elt, value, &tmp_err)) {
+ memprintf(err, "%s, %s", err && *err ? *err : "", tmp_err);
+ ha_free(&tmp_err);
}
found = 1;
}