]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: h2: fix reverse if no timeout defined
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 24 Aug 2023 15:32:50 +0000 (17:32 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 24 Aug 2023 15:58:14 +0000 (17:58 +0200)
h2c.task is not allocated in h2_init() if timeout client/server is not
defined depending on the connection side. This caused crash on
connection reverse due to systematic requeuing of h2c.task in
h2_conn_reverse().

To fix this, check h2c.task in h2_conn_reverse(). If old timeout was
undefined but new one is, h2c.task must be allocated as it was not in
h2_init(). On the opposite situation, if old timeout was defined and new
one is not, h2c.task is freed. In this case, or if neither timeout are
defined, skip the task requeuing.

This bug is easily reproduced by using reverse bind or server with
undefined timeout client/server depending on the connection reverse
direction.

This bug has been introduced by reverse connect support.
No need to backport it.

src/mux_h2.c

index aceee8bec0f7b24fc55814a258ef4b967792b3b0..deb2cc29734cc2caf0cf40a59187249dd9980292 100644 (file)
@@ -3294,8 +3294,27 @@ static int h2_conn_reverse(struct h2c *h2c)
                h2c->flags |= H2_CF_DEM_TOOMANY;
        }
 
-       h2c->task->expire = tick_add(now_ms, h2c->timeout);
-       task_queue(h2c->task);
+       /* If only the new side has a defined timeout, task must be allocated.
+        * On the contrary, if only old side has a timeout, it must be freed.
+        */
+       if (!h2c->task && tick_isset(h2c->timeout)) {
+               h2c->task = task_new_here();
+               if (!h2c->task)
+                       goto err;
+
+               h2c->task->process = h2_timeout_task;
+               h2c->task->context = h2c;
+       }
+       else if (!tick_isset(h2c->timeout)) {
+               task_destroy(h2c->task);
+               h2c->task = NULL;
+       }
+
+       /* Requeue task if instantiated with the new timeout value. */
+       if (h2c->task) {
+               h2c->task->expire = tick_add(now_ms, h2c->timeout);
+               task_queue(h2c->task);
+       }
 
        TRACE_LEAVE(H2_EV_H2C_WAKE, h2c->conn);
        return 1;