BUG/MEDIUM: capture: capture.{req,res}.* crash without a stream
authorWilly Tarreau <w@1wt.eu>
Wed, 29 Apr 2020 09:44:54 +0000 (11:44 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 1 May 2020 10:21:16 +0000 (12:21 +0200)
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.

(cherry picked from commit 0898c2d2f2c5ae043a443550992efd90ec18b2ab)
Signed-off-by: Willy Tarreau <w@1wt.eu>

src/http_fetch.c

index 29a26bc..723aa1f 100644 (file)
@@ -1333,12 +1333,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)
@@ -1357,12 +1361,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)
@@ -1380,9 +1388,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;
 
@@ -1405,10 +1417,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;
 
@@ -1443,8 +1459,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;
 
@@ -1465,8 +1485,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;