[tarantool-patches] [PATCH] httpc: fix bug with segfault by wrong headers

Roman Khabibov roman.habibov at tarantool.org
Sun Jun 16 18:24:09 MSK 2019


There wasn't lua_istable() checking for field 'headers'.

Closes #4281
---

Branch: https://github.com/tarantool/tarantool/compare/romanhabibov/gh-4281-header
Issue: https://github.com/tarantool/tarantool/issues/4281

 src/lua/httpc.c                   | 66 ++++++++++++++++++++-----------
 test/app-tap/http_client.test.lua | 17 ++++++++
 2 files changed, 61 insertions(+), 22 deletions(-)

diff --git a/src/lua/httpc.c b/src/lua/httpc.c
index bc8d498ba..bd6a7995e 100644
--- a/src/lua/httpc.c
+++ b/src/lua/httpc.c
@@ -133,6 +133,43 @@ parse_headers(lua_State *L, char *buffer, size_t len,
 	lua_settable(L, -3);
 	return 0;
 }
+
+/**
+ * Process the Lua table of headers that lies 2 below the top of
+ * @a L Lua stack. In case of an error, push it on  @a L.
+ *
+ * Added to reduce nesting.
+ *
+ * @param L Lua stack.
+ * @param req http request.
+ *
+ * @retval 0 on success.
+ * @retval non-zero on error.
+ */
+static int
+process_headers(struct lua_State *L, struct httpc_request *req)
+{
+	while (lua_next(L, -2) != 0) {
+		int header_type = lua_type(L, -1);
+		if (header_type != LUA_TSTRING) {
+			const char *err_msg = "headers must be string or table"\
+				" with \"__tostring\"";
+			if (header_type != LUA_TTABLE)
+				return luaL_error(L, err_msg);
+			else if (!luaL_getmetafield(L, -1, "__tostring"))
+				return luaL_error(L, err_msg);
+			lua_pop(L, 1);
+		}
+		if (httpc_set_header(req, "%s: %s", lua_tostring(L, -2),
+				     lua_tostring(L, -1)) < 0) {
+			httpc_request_delete(req);
+			return luaT_error(L);
+		}
+		lua_pop(L, 1);
+	}
+	return 0;
+}
+
 /* }}}
  */
 
@@ -177,28 +214,13 @@ luaT_httpc_request(lua_State *L)
 	lua_getfield(L, 5, "headers");
 	if (!lua_isnil(L, -1)) {
 		lua_pushnil(L);
-		while (lua_next(L, -2) != 0) {
-			int header_type = lua_type(L, -1);
-			if (header_type != LUA_TSTRING) {
-				const char *err_msg =
-					"headers must be string or table "\
-					"with \"__tostring\"";
-				if (header_type != LUA_TTABLE) {
-					return luaL_error(L, err_msg);
-				} else if (!luaL_getmetafield(L, -1,
-							      "__tostring")) {
-					return luaL_error(L, err_msg);
-				}
-				lua_pop(L, 1);
-			}
-			if (httpc_set_header(req, "%s: %s",
-					     lua_tostring(L, -2),
-					     lua_tostring(L, -1)) < 0) {
-				httpc_request_delete(req);
-				return luaT_error(L);
-			}
-			lua_pop(L, 1);
-		}
+		int ret;
+		if (lua_istable(L, -2) != 0)
+			ret = process_headers(L, req);
+		else
+			return luaL_error(L, "field \"headers\" must be table");
+		if (ret != 0)
+			return ret;
 	}
 	lua_pop(L, 1);
 
diff --git a/test/app-tap/http_client.test.lua b/test/app-tap/http_client.test.lua
index 680c78b35..9cb8c3a74 100755
--- a/test/app-tap/http_client.test.lua
+++ b/test/app-tap/http_client.test.lua
@@ -276,6 +276,7 @@ end
 -- gh-3679 allow only headers can be converted to string
 local function test_request_headers(test, url, opts)
     local exp_err = 'headers must be string or table with "__tostring"'
+    local exp_err_non_table = 'field "headers" must be table'
     local cases = {
         {
             'string header',
@@ -324,6 +325,22 @@ local function test_request_headers(test, url, opts)
             opts = {headers = {aaa = setmetatable({}, {})}},
             exp_err = exp_err,
         },
+-- gh-4281 allow only field 'headers' can be table
+        {
+            'non-table \'headers\'',
+            opts = {headers = 'aaa'},
+            exp_err = exp_err_non_table,
+        },
+        {
+            'non-table \'headers\'',
+            opts = {headers = 1},
+            exp_err = exp_err_non_table,
+        },
+        {
+            'non-table \'headers\'',
+            opts = {headers = box.NULL},
+            exp_err = exp_err_non_table,
+        },
     }
     test:plan(#cases)
 
-- 
2.20.1 (Apple Git-117)





More information about the Tarantool-patches mailing list