]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: lua: Forbid calls to Channel functions for LUA scripts in HTTP proxies
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 13 Dec 2018 20:56:45 +0000 (21:56 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 14 Dec 2018 15:04:00 +0000 (16:04 +0100)
Functions from then Channel class are now forbidden for LUA scripts called from
HTTP proxies. These functions totally hijacked the HTTP parser, leaving it in an
undefined state. This patch is tagged as MAJOR because it could be see as a
compatibility breakage. But a LUA script using one of these functions has a very
low probablity to work correctly except by chance.

So, concretely, following functions are concerned: Channel.get, Channel.dup,
Channel.getline, Channel.set, Channel.append, Channel.send,
Channel.forward. Others remain available.

src/hlua.c

index 5dd88f2f19454b21b2ec5c8fd59167fa2a3cc350..810489fb71e3dfaa86f00e79e2c4cc90d6920a5f 100644 (file)
@@ -2685,34 +2685,6 @@ __LJMP static int hlua_socket_new(lua_State *L)
  *
  */
 
-/* The state between the channel data and the HTTP parser state can be
- * inconsistent, so reset the parser and call it again. Warning, this
- * action does not revalidate the request and does not send a 400 if the modified
- * request is not valid.
- *
- * This function never fails. The direction is set using dir, which equals
- * either SMP_OPT_DIR_REQ or SMP_OPT_DIR_RES.
- */
-static void hlua_resynchonize_proto(struct stream *stream, int dir)
-{
-       /* Protocol HTTP. */
-       if (stream->be->mode == PR_MODE_HTTP) {
-
-               if (dir == SMP_OPT_DIR_REQ)
-                       http_txn_reset_req(stream->txn);
-               else if (dir == SMP_OPT_DIR_RES)
-                       http_txn_reset_res(stream->txn);
-
-               if (stream->txn->hdr_idx.v)
-                       hdr_idx_init(&stream->txn->hdr_idx);
-
-               if (dir == SMP_OPT_DIR_REQ)
-                       http_msg_analyzer(&stream->txn->req, &stream->txn->hdr_idx);
-               else if (dir == SMP_OPT_DIR_RES)
-                       http_msg_analyzer(&stream->txn->rsp, &stream->txn->hdr_idx);
-       }
-}
-
 /* This function is called before the Lua execution. It stores
  * the differents parsers state before executing some Lua code.
  */
@@ -2831,6 +2803,9 @@ __LJMP static int hlua_channel_dup_yield(lua_State *L, int status, lua_KContext
 
        chn = MAY_LJMP(hlua_checkchannel(L, 1));
 
+       if (chn_strm(chn)->be->mode == PR_MODE_HTTP)
+               WILL_LJMP(lua_error(L));
+
        if (_hlua_channel_dup(chn, L) == 0)
                MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_dup_yield, TICK_ETERNITY, 0));
        return 1;
@@ -2856,6 +2831,9 @@ __LJMP static int hlua_channel_get_yield(lua_State *L, int status, lua_KContext
 
        chn = MAY_LJMP(hlua_checkchannel(L, 1));
 
+       if (chn_strm(chn)->be->mode == PR_MODE_HTTP)
+               WILL_LJMP(lua_error(L));
+
        ret = _hlua_channel_dup(chn, L);
        if (unlikely(ret == 0))
                MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_yield, TICK_ETERNITY, 0));
@@ -2864,7 +2842,6 @@ __LJMP static int hlua_channel_get_yield(lua_State *L, int status, lua_KContext
                return 1;
 
        b_sub(&chn->buf, ret);
-       hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
        return 1;
 }
 
@@ -2894,6 +2871,9 @@ __LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KCont
 
        chn = MAY_LJMP(hlua_checkchannel(L, 1));
 
+       if (chn_strm(chn)->be->mode == PR_MODE_HTTP)
+               WILL_LJMP(lua_error(L));
+
        ret = ci_getline_nc(chn, &blk1, &len1, &blk2, &len2);
        if (ret == 0)
                MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
@@ -2912,7 +2892,6 @@ __LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KCont
        }
        luaL_pushresult(&b);
        b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn) + len,  NULL, 0);
-       hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
        return 1;
 }
 
@@ -2940,6 +2919,9 @@ __LJMP static int hlua_channel_append_yield(lua_State *L, int status, lua_KConte
        int ret;
        int max;
 
+       if (chn_strm(chn)->be->mode == PR_MODE_HTTP)
+               WILL_LJMP(lua_error(L));
+
        /* Check if the buffer is available because HAProxy doesn't allocate
         * the request buffer if its not required.
         */
@@ -2964,7 +2946,6 @@ __LJMP static int hlua_channel_append_yield(lua_State *L, int status, lua_KConte
        l += ret;
        lua_pop(L, 1);
        lua_pushinteger(L, l);
-       hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
 
        max = channel_recv_limit(chn) - b_data(&chn->buf);
        if (max == 0 && co_data(chn) == 0) {
@@ -3010,6 +2991,9 @@ __LJMP static int hlua_channel_set(lua_State *L)
        chn = MAY_LJMP(hlua_checkchannel(L, 1));
        lua_pushinteger(L, 0);
 
+       if (chn_strm(chn)->be->mode == PR_MODE_HTTP)
+               WILL_LJMP(lua_error(L));
+
        b_set_data(&chn->buf, co_data(chn));
 
        return MAY_LJMP(hlua_channel_append_yield(L, 0, 0));
@@ -3029,6 +3013,9 @@ __LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext
        int max;
        struct hlua *hlua = hlua_gethlua(L);
 
+       if (chn_strm(chn)->be->mode == PR_MODE_HTTP)
+               WILL_LJMP(lua_error(L));
+
        if (unlikely(channel_output_closed(chn))) {
                lua_pushinteger(L, -1);
                return 1;
@@ -3129,6 +3116,10 @@ __LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KCont
        struct hlua *hlua = hlua_gethlua(L);
 
        chn = MAY_LJMP(hlua_checkchannel(L, 1));
+
+       if (chn_strm(chn)->be->mode == PR_MODE_HTTP)
+               WILL_LJMP(lua_error(L));
+
        len = MAY_LJMP(luaL_checkinteger(L, 2));
        l = MAY_LJMP(luaL_checkinteger(L, -1));