[4.1] 713be80 Close race condition on HTTP1 session step counter

Martin Blix Grydeland martin at varnish-software.com
Fri Dec 9 11:20:05 CET 2016


commit 713be801409a3fabd68f450a32c0f49b263a2f3d
Author: Martin Blix Grydeland <martin at varnish-software.com>
Date:   Thu Dec 8 17:43:23 2016 +0100

    Close race condition on HTTP1 session step counter
    
    When going on a waitinglist, the HTTP1 step counter was set to
    S_STP_H1BUSY to allow conditions to be checked on return specific to
    having been on a waitinglist. Though the step counter was set after
    entering the waitinglist, and if the session was rescheduled
    immediately on another thread a race opened which would mess up the
    state handling.
    
    Fix this by elliminating the S_STP_H1BUSY step, and having condition
    checks on req->hash_objhead in the S_STP_H1PROC state to handle the
    waitinglist return specific checks.
    
    The panic output has been changed to include the req->hash_objhead
    pointer if set. This exposes the waitinglist condition in the panic
    output which would otherwise be hidden by the removal of the
    S_STP_H1BUSY step.
    
    Fixes: #2117

diff --git a/bin/varnishd/cache/cache_panic.c b/bin/varnishd/cache/cache_panic.c
index 589f9f5..de5ce0c 100644
--- a/bin/varnishd/cache/cache_panic.c
+++ b/bin/varnishd/cache/cache_panic.c
@@ -345,6 +345,8 @@ pan_req(struct vsb *vsb, const struct req *req)
 		VSB_printf(vsb, "step = %s,\n", stp);
 	else
 		VSB_printf(vsb, "step = 0x%x,\n", req->req_step);
+	if (req->hash_objhead)
+		VSB_printf(vsb, "hash_objhead = %p\n", req->hash_objhead);
 
 	VSB_printf(vsb, "req_body = %s,\n",
 	    reqbody_status_2str(req->req_body_status));
diff --git a/bin/varnishd/http1/cache_http1_fsm.c b/bin/varnishd/http1/cache_http1_fsm.c
index ad9b069..9b4313e 100644
--- a/bin/varnishd/http1/cache_http1_fsm.c
+++ b/bin/varnishd/http1/cache_http1_fsm.c
@@ -247,27 +247,22 @@ HTTP1_Session(struct worker *wrk, struct req *req)
 			req->req_step = R_STP_RECV;
 			sp->sess_step = S_STP_H1PROC;
 			break;
-		case S_STP_H1BUSY:
-			/*
-			 * Return from waitinglist.
-			 * Check to see if the remote has left.
-			 */
-			if (VTCP_check_hup(sp->fd)) {
-				AN(req->hash_objhead);
+		case S_STP_H1PROC:
+			req->transport = &http1_transport;
+			req->task.func = SES_Proto_Req;
+			req->task.priv = req;
+			if (req->hash_objhead && VTCP_check_hup(sp->fd)) {
+				/* Return from waitinglist and the remote
+				   has left. */
 				(void)HSH_DerefObjHead(wrk, &req->hash_objhead);
 				AZ(req->hash_objhead);
 				SES_Close(sp, SC_REM_CLOSE);
 				AN(Req_Cleanup(sp, wrk, req));
 				return;
 			}
-			sp->sess_step = S_STP_H1PROC;
-			break;
-		case S_STP_H1PROC:
-			req->transport = &http1_transport;
-			req->task.func = SES_Proto_Req;
-			req->task.priv = req;
 			if (CNT_Request(wrk, req) == REQ_FSM_DISEMBARK) {
-				sp->sess_step = S_STP_H1BUSY;
+				/* Have been placed on waitinglist. Any
+				   changes to req and sp are unsafe. */
 				return;
 			}
 			req->transport = NULL;
diff --git a/include/tbl/steps.h b/include/tbl/steps.h
index 4756d44..bd6c1eb 100644
--- a/include/tbl/steps.h
+++ b/include/tbl/steps.h
@@ -34,7 +34,6 @@
 SESS_STEP(h1newsess,	H1NEWSESS)
 SESS_STEP(h1newreq,	H1NEWREQ)
 SESS_STEP(h1proc,	H1PROC)
-SESS_STEP(h1busy,	H1BUSY)
 SESS_STEP(h1cleanup,	H1CLEANUP)
 SESS_STEP(h1_last,	H1_LAST)
 



More information about the varnish-commit mailing list