mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-05-01 23:39:32 +00:00
BUG/MAJOR: lua: segfault after the channel data is modified by some Lua action.
When an action or a fetch modify the channel data, the http request parser pointer become inconsistent. This patch detects the modification and call again the parser.
This commit is contained in:
parent
84e73c8882
commit
d75cb0fce6
74
src/hlua.c
74
src/hlua.c
@ -2365,6 +2365,57 @@ __LJMP static int hlua_socket_new(lua_State *L)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* The state between the channel data and the HTTP parser state can be
|
||||||
|
* unconsistent, so reset the parser and call it again. Warning, this
|
||||||
|
* action not revalidate the request and not send a 400 if the modified
|
||||||
|
* resuest is not valid.
|
||||||
|
*
|
||||||
|
* This function never fails. If dir is 0 we are a request, if it is 1
|
||||||
|
* its a response.
|
||||||
|
*/
|
||||||
|
static void hlua_resynchonize_proto(struct stream *stream, int dir)
|
||||||
|
{
|
||||||
|
/* Protocol HTTP. */
|
||||||
|
if (stream->be->mode == PR_MODE_HTTP) {
|
||||||
|
|
||||||
|
if (dir == 0)
|
||||||
|
http_txn_reset_req(stream->txn);
|
||||||
|
else if (dir == 1)
|
||||||
|
http_txn_reset_res(stream->txn);
|
||||||
|
|
||||||
|
if (stream->txn->hdr_idx.v)
|
||||||
|
hdr_idx_init(&stream->txn->hdr_idx);
|
||||||
|
|
||||||
|
if (dir == 0)
|
||||||
|
http_msg_analyzer(&stream->txn->req, &stream->txn->hdr_idx);
|
||||||
|
else if (dir == 1)
|
||||||
|
http_msg_analyzer(&stream->txn->rsp, &stream->txn->hdr_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the protocole integrity after the Lua manipulations.
|
||||||
|
* Close the stream and returns 0 if fails, otherwise returns 1.
|
||||||
|
*/
|
||||||
|
static int hlua_check_proto(struct stream *stream, int dir)
|
||||||
|
{
|
||||||
|
const struct chunk msg = { .len = 0 };
|
||||||
|
|
||||||
|
/* Protocol HTTP. The message parsing state must be in accord
|
||||||
|
* with the request or response state.
|
||||||
|
*/
|
||||||
|
if (stream->be->mode == PR_MODE_HTTP) {
|
||||||
|
if (dir == 0 && stream->txn->req.msg_state < HTTP_MSG_BODY) {
|
||||||
|
stream_int_retnclose(&stream->si[0], &msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (dir == 1 && stream->txn->rsp.msg_state < HTTP_MSG_BODY) {
|
||||||
|
stream_int_retnclose(&stream->si[0], &msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns the struct hlua_channel join to the class channel in the
|
/* Returns the struct hlua_channel join to the class channel in the
|
||||||
* stack entry "ud" or throws an argument error.
|
* stack entry "ud" or throws an argument error.
|
||||||
*/
|
*/
|
||||||
@ -2469,6 +2520,7 @@ __LJMP static int hlua_channel_get_yield(lua_State *L, int status, lua_KContext
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
chn->buf->i -= ret;
|
chn->buf->i -= ret;
|
||||||
|
hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2516,6 +2568,7 @@ __LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KCont
|
|||||||
}
|
}
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
buffer_replace2(chn->buf, chn->buf->p, chn->buf->p + len, NULL, 0);
|
buffer_replace2(chn->buf, chn->buf->p, chn->buf->p + len, NULL, 0);
|
||||||
|
hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2559,6 +2612,7 @@ __LJMP static int hlua_channel_append_yield(lua_State *L, int status, lua_KConte
|
|||||||
l += ret;
|
l += ret;
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
lua_pushinteger(L, l);
|
lua_pushinteger(L, l);
|
||||||
|
hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
|
||||||
|
|
||||||
max = channel_recv_limit(chn) - buffer_len(chn->buf);
|
max = channel_recv_limit(chn) - buffer_len(chn->buf);
|
||||||
if (max == 0 && chn->buf->o == 0) {
|
if (max == 0 && chn->buf->o == 0) {
|
||||||
@ -4224,6 +4278,8 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
|
|||||||
switch (hlua_ctx_resume(&stream->hlua, 0)) {
|
switch (hlua_ctx_resume(&stream->hlua, 0)) {
|
||||||
/* finished. */
|
/* finished. */
|
||||||
case HLUA_E_OK:
|
case HLUA_E_OK:
|
||||||
|
if (!hlua_check_proto(stream, !(smp->opt & SMP_OPT_DIR_REQ)))
|
||||||
|
return 0;
|
||||||
/* Convert the returned value in sample. */
|
/* Convert the returned value in sample. */
|
||||||
hlua_lua2smp(stream->hlua.T, -1, smp);
|
hlua_lua2smp(stream->hlua.T, -1, smp);
|
||||||
lua_pop(stream->hlua.T, 1);
|
lua_pop(stream->hlua.T, 1);
|
||||||
@ -4234,11 +4290,13 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
|
|||||||
|
|
||||||
/* yield. */
|
/* yield. */
|
||||||
case HLUA_E_AGAIN:
|
case HLUA_E_AGAIN:
|
||||||
|
hlua_check_proto(stream, !(smp->opt & SMP_OPT_DIR_REQ));
|
||||||
SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
|
SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* finished with error. */
|
/* finished with error. */
|
||||||
case HLUA_E_ERRMSG:
|
case HLUA_E_ERRMSG:
|
||||||
|
hlua_check_proto(stream, !(smp->opt & SMP_OPT_DIR_REQ));
|
||||||
/* Display log. */
|
/* Display log. */
|
||||||
SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
|
SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
|
||||||
fcn->name, lua_tostring(stream->hlua.T, -1));
|
fcn->name, lua_tostring(stream->hlua.T, -1));
|
||||||
@ -4246,6 +4304,7 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case HLUA_E_ERR:
|
case HLUA_E_ERR:
|
||||||
|
hlua_check_proto(stream, !(smp->opt & SMP_OPT_DIR_REQ));
|
||||||
/* Display log. */
|
/* Display log. */
|
||||||
SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
|
SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
|
||||||
|
|
||||||
@ -4386,12 +4445,13 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
|
|||||||
{
|
{
|
||||||
char **arg;
|
char **arg;
|
||||||
unsigned int analyzer;
|
unsigned int analyzer;
|
||||||
|
int dir;
|
||||||
|
|
||||||
switch (rule->from) {
|
switch (rule->from) {
|
||||||
case ACT_F_TCP_REQ_CNT: analyzer = AN_REQ_INSPECT_FE ; break;
|
case ACT_F_TCP_REQ_CNT: analyzer = AN_REQ_INSPECT_FE ; dir = 0; break;
|
||||||
case ACT_F_TCP_RES_CNT: analyzer = AN_RES_INSPECT ; break;
|
case ACT_F_TCP_RES_CNT: analyzer = AN_RES_INSPECT ; dir = 1; break;
|
||||||
case ACT_F_HTTP_REQ: analyzer = AN_REQ_HTTP_PROCESS_FE; break;
|
case ACT_F_HTTP_REQ: analyzer = AN_REQ_HTTP_PROCESS_FE; dir = 0; break;
|
||||||
case ACT_F_HTTP_RES: analyzer = AN_RES_HTTP_PROCESS_BE; break;
|
case ACT_F_HTTP_RES: analyzer = AN_RES_HTTP_PROCESS_BE; dir = 1; break;
|
||||||
default:
|
default:
|
||||||
SEND_ERR(px, "Lua: internal error while execute action.\n");
|
SEND_ERR(px, "Lua: internal error while execute action.\n");
|
||||||
return ACT_RET_CONT;
|
return ACT_RET_CONT;
|
||||||
@ -4461,6 +4521,8 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
|
|||||||
switch (hlua_ctx_resume(&s->hlua, 1)) {
|
switch (hlua_ctx_resume(&s->hlua, 1)) {
|
||||||
/* finished. */
|
/* finished. */
|
||||||
case HLUA_E_OK:
|
case HLUA_E_OK:
|
||||||
|
if (!hlua_check_proto(s, dir))
|
||||||
|
return ACT_RET_ERR;
|
||||||
return ACT_RET_CONT;
|
return ACT_RET_CONT;
|
||||||
|
|
||||||
/* yield. */
|
/* yield. */
|
||||||
@ -4487,6 +4549,8 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
|
|||||||
|
|
||||||
/* finished with error. */
|
/* finished with error. */
|
||||||
case HLUA_E_ERRMSG:
|
case HLUA_E_ERRMSG:
|
||||||
|
if (!hlua_check_proto(s, dir))
|
||||||
|
return ACT_RET_ERR;
|
||||||
/* Display log. */
|
/* Display log. */
|
||||||
SEND_ERR(px, "Lua function '%s': %s.\n",
|
SEND_ERR(px, "Lua function '%s': %s.\n",
|
||||||
rule->arg.hlua_rule->fcn.name, lua_tostring(s->hlua.T, -1));
|
rule->arg.hlua_rule->fcn.name, lua_tostring(s->hlua.T, -1));
|
||||||
@ -4494,6 +4558,8 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
|
|||||||
return ACT_RET_CONT;
|
return ACT_RET_CONT;
|
||||||
|
|
||||||
case HLUA_E_ERR:
|
case HLUA_E_ERR:
|
||||||
|
if (!hlua_check_proto(s, dir))
|
||||||
|
return ACT_RET_ERR;
|
||||||
/* Display log. */
|
/* Display log. */
|
||||||
SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
|
SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
|
||||||
rule->arg.hlua_rule->fcn.name);
|
rule->arg.hlua_rule->fcn.name);
|
||||||
|
Loading…
Reference in New Issue
Block a user