BUG/MAJOR: stream: fix session abort on resource shortage

In 1.6-dev2, commit 32990b5 ("MEDIUM: session: remove the task pointer
from the session") introduced a bug which can sometimes crash the process
on resource shortage. When stream_complete() returns -1, it has already
reattached the connection to the stream, then kill_mini_session() is
called and still expects to find the task in conn->owner. Note that
since this commit, the code has moved a bit and is now in stream_new()
but the problem remains the same.

Given that we already know the task around these places, let's simply
pass the task to kill_mini_session().

The conditions currently at risk are :
  - failure to initialize filters for the new stream (lack of memory or
    any filter returning < 0 on attach())
  - failure to attach filters (any filter returning < 0 on stream_start())
  - frontend's accept() returning < 0 (allocation failure)

This fix is needed in 1.7 and 1.6.
This commit is contained in:
Willy Tarreau 2016-12-04 20:05:16 +01:00
parent 6962f4e0d6
commit 92b10c954d

View File

@ -342,11 +342,10 @@ static void session_prepare_log_prefix(struct session *sess)
* disabled and finally kills the file descriptor. This function requires that * disabled and finally kills the file descriptor. This function requires that
* sess->origin points to the incoming connection. * sess->origin points to the incoming connection.
*/ */
static void session_kill_embryonic(struct session *sess) static void session_kill_embryonic(struct session *sess, struct task *task)
{ {
int level = LOG_INFO; int level = LOG_INFO;
struct connection *conn = __objt_conn(sess->origin); struct connection *conn = __objt_conn(sess->origin);
struct task *task = conn->owner;
unsigned int log = sess->fe->to_log; unsigned int log = sess->fe->to_log;
const char *err_msg; const char *err_msg;
@ -417,7 +416,7 @@ static struct task *session_expire_embryonic(struct task *t)
if (!(t->state & TASK_WOKEN_TIMER)) if (!(t->state & TASK_WOKEN_TIMER))
return t; return t;
session_kill_embryonic(sess); session_kill_embryonic(sess, t);
return NULL; return NULL;
} }
@ -457,7 +456,7 @@ static int conn_complete_session(struct connection *conn)
return 0; return 0;
fail: fail:
session_kill_embryonic(sess); session_kill_embryonic(sess, task);
return -1; return -1;
} }
@ -470,7 +469,7 @@ static int conn_update_session(struct connection *conn)
struct session *sess = task->context; struct session *sess = task->context;
if (conn->flags & CO_FL_ERROR) { if (conn->flags & CO_FL_ERROR) {
session_kill_embryonic(sess); session_kill_embryonic(sess, task);
return -1; return -1;
} }
return 0; return 0;