From 0898c2d2f2c5ae043a443550992efd90ec18b2ab Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 29 Apr 2020 11:44:54 +0200 Subject: [PATCH] BUG/MEDIUM: capture: capture.{req,res}.* crash without a stream Since commit 5f940703b3 ("MINOR: log: Don't depends on a stream to process samples in log-format string") it has become quite obvious that a few sample fetch functions and converters were still heavily dependent on the presence of a stream without testing for it. The capture.req.hdr, capture.res.hdr, capture.req.method, capture.req.uri, capture.req.ver and capture.res.ver sample fetches used to assume the presence of a stream, which is not necessarily the case (especially after the commit above) and would crash haproxy if incorrectly used. Let's make sure they check for this stream. This fix adds a check for the stream's existence, and should be backported to all stable versions up to 1.6. --- src/http_fetch.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/http_fetch.c b/src/http_fetch.c index 9cfcee2ab..0d01b797e 100644 --- a/src/http_fetch.c +++ b/src/http_fetch.c @@ -1328,12 +1328,16 @@ static int smp_fetch_http_auth_grp(const struct arg *args, struct sample *smp, c */ static int smp_fetch_capture_req_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct proxy *fe = strm_fe(smp->strm); + struct proxy *fe; int idx; if (!args || args->type != ARGT_SINT) return 0; + if (!smp->strm) + return 0; + + fe = strm_fe(smp->strm); idx = args->data.sint; if (idx > (fe->nb_req_cap - 1) || smp->strm->req_cap == NULL || smp->strm->req_cap[idx] == NULL) @@ -1352,12 +1356,16 @@ static int smp_fetch_capture_req_hdr(const struct arg *args, struct sample *smp, */ static int smp_fetch_capture_res_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct proxy *fe = strm_fe(smp->strm); + struct proxy *fe; int idx; if (!args || args->type != ARGT_SINT) return 0; + if (!smp->strm) + return 0; + + fe = strm_fe(smp->strm); idx = args->data.sint; if (idx > (fe->nb_rsp_cap - 1) || smp->strm->res_cap == NULL || smp->strm->res_cap[idx] == NULL) @@ -1375,9 +1383,13 @@ static int smp_fetch_capture_res_hdr(const struct arg *args, struct sample *smp, static int smp_fetch_capture_req_method(const struct arg *args, struct sample *smp, const char *kw, void *private) { struct buffer *temp; - struct http_txn *txn = smp->strm->txn; + struct http_txn *txn; char *ptr; + if (!smp->strm) + return 0; + + txn = smp->strm->txn; if (!txn || !txn->uri) return 0; @@ -1400,10 +1412,14 @@ static int smp_fetch_capture_req_method(const struct arg *args, struct sample *s /* Extracts the path in the HTTP request, the txn->uri should be filled before the call */ static int smp_fetch_capture_req_uri(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct http_txn *txn = smp->strm->txn; + struct http_txn *txn; struct ist path; const char *ptr; + if (!smp->strm) + return 0; + + txn = smp->strm->txn; if (!txn || !txn->uri) return 0; @@ -1438,8 +1454,12 @@ static int smp_fetch_capture_req_uri(const struct arg *args, struct sample *smp, */ static int smp_fetch_capture_req_ver(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct http_txn *txn = smp->strm->txn; + struct http_txn *txn; + if (!smp->strm) + return 0; + + txn = smp->strm->txn; if (!txn || txn->req.msg_state >= HTTP_MSG_BODY) return 0; @@ -1460,8 +1480,12 @@ static int smp_fetch_capture_req_ver(const struct arg *args, struct sample *smp, */ static int smp_fetch_capture_res_ver(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct http_txn *txn = smp->strm->txn; + struct http_txn *txn; + if (!smp->strm) + return 0; + + txn = smp->strm->txn; if (!txn || txn->rsp.msg_state >= HTTP_MSG_BODY) return 0;