Skip to content

Commit cb82db3

Browse files
bugfix: wrong arguments of setkeepalive() result in the compromise of data integrity.
1 parent a5c924b commit cb82db3

File tree

2 files changed

+166
-21
lines changed

2 files changed

+166
-21
lines changed

src/ngx_stream_lua_socket_tcp.c

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5250,6 +5250,34 @@ ngx_stream_lua_socket_tcp_setkeepalive(lua_State *L)
52505250

52515251
luaL_checktype(L, 1, LUA_TTABLE);
52525252

5253+
r = ngx_stream_lua_get_req(L);
5254+
if (r == NULL) {
5255+
return luaL_error(L, "no request found");
5256+
}
5257+
5258+
llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);
5259+
5260+
/* luaL_checkinteger will throw error if the argument is not a number.
5261+
* e.g.: bad argument \#2 to '?' (number expected, got string)
5262+
*
5263+
* We should check the argument in advance; otherwise,
5264+
* throwing an exception in the middle can compromise data integrity.
5265+
* e.g.: set pc->connection to NULL without following cleanup.
5266+
*/
5267+
if (n >= 2 && !lua_isnil(L, 2)) {
5268+
timeout = (ngx_msec_t) luaL_checkinteger(L, 2);
5269+
5270+
} else {
5271+
timeout = llcf->keepalive_timeout;
5272+
}
5273+
5274+
if (n >= 3 && !lua_isnil(L, 3)) {
5275+
pool_size = luaL_checkinteger(L, 3);
5276+
5277+
} else {
5278+
pool_size = llcf->pool_size;
5279+
}
5280+
52535281
lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
52545282
u = lua_touserdata(L, -1);
52555283
lua_pop(L, 1);
@@ -5271,11 +5299,6 @@ ngx_stream_lua_socket_tcp_setkeepalive(lua_State *L)
52715299
return 2;
52725300
}
52735301

5274-
r = ngx_stream_lua_get_req(L);
5275-
if (r == NULL) {
5276-
return luaL_error(L, "no request found");
5277-
}
5278-
52795302
if (u->request != r) {
52805303
return luaL_error(L, "bad request");
52815304
}
@@ -5349,18 +5372,9 @@ ngx_stream_lua_socket_tcp_setkeepalive(lua_State *L)
53495372

53505373
/* stack: obj timeout? size? pools cache_key */
53515374

5352-
llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);
5353-
53545375
if (spool == NULL) {
53555376
/* create a new socket pool for the current peer key */
53565377

5357-
if (n >= 3 && !lua_isnil(L, 3)) {
5358-
pool_size = luaL_checkinteger(L, 3);
5359-
5360-
} else {
5361-
pool_size = llcf->pool_size;
5362-
}
5363-
53645378
if (pool_size <= 0) {
53655379
msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i",
53665380
pool_size);
@@ -5425,13 +5439,6 @@ ngx_stream_lua_socket_tcp_setkeepalive(lua_State *L)
54255439
ngx_del_timer(c->write);
54265440
}
54275441

5428-
if (n >= 2 && !lua_isnil(L, 2)) {
5429-
timeout = (ngx_msec_t) luaL_checkinteger(L, 2);
5430-
5431-
} else {
5432-
timeout = llcf->keepalive_timeout;
5433-
}
5434-
54355442
#if (NGX_DEBUG)
54365443
if (timeout == 0) {
54375444
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,

t/068-socket-keepalive.t

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2354,3 +2354,141 @@ ok
23542354
lua tcp socket abort queueing
23552355
--- no_error_log
23562356
[error]
2357+
2358+
2359+
2360+
=== TEST 53: wrong first argument of setkeepalive()
2361+
--- config
2362+
location /foo {
2363+
server_tokens off;
2364+
keepalive_timeout 60s;
2365+
echo foo;
2366+
}
2367+
--- stream_server_config
2368+
content_by_lua_block {
2369+
local sock = ngx.socket.tcp()
2370+
sock:settimeouts(1000, 1000, 1000)
2371+
2372+
local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_PORT)
2373+
if not ok then
2374+
ngx.say("failed to connect: ", err)
2375+
return
2376+
end
2377+
2378+
ngx.say("connected: ", ok)
2379+
2380+
local req = "GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n"
2381+
2382+
local bytes, err = sock:send(req)
2383+
if not bytes then
2384+
ngx.say("failed to send request: ", err)
2385+
return
2386+
end
2387+
2388+
ngx.say("request sent: ", bytes)
2389+
2390+
local reader = sock:receiveuntil("\r\n0\r\n\r\n")
2391+
local data, err = reader()
2392+
if not data then
2393+
ngx.say("failed to receive response body: ", err)
2394+
return
2395+
end
2396+
2397+
ngx.say("received response of ", #data, " bytes")
2398+
2399+
local ok, err = sock:setkeepalive()
2400+
if not ok then
2401+
ngx.say("failed to set reusable: ", err)
2402+
return
2403+
end
2404+
2405+
ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_PORT)
2406+
if not ok then
2407+
ngx.say("failed to connect: ", err)
2408+
return
2409+
end
2410+
2411+
local ok, err = sock:setkeepalive("not a number")
2412+
if not ok then
2413+
ngx.say("failed to set reusable: ", err)
2414+
return
2415+
end
2416+
}
2417+
--- stream_response
2418+
connected: 1
2419+
request sent: 61
2420+
received response of 156 bytes
2421+
--- error_log eval
2422+
qr/\Qbad argument #1 to 'setkeepalive' (number expected, got string)\E/
2423+
--- no_error_log
2424+
[crit]
2425+
--- timeout: 4
2426+
2427+
2428+
2429+
=== TEST 54: wrong second argument of setkeepalive()
2430+
--- config
2431+
location /foo {
2432+
server_tokens off;
2433+
keepalive_timeout 60s;
2434+
echo foo;
2435+
}
2436+
--- stream_server_config
2437+
content_by_lua_block {
2438+
local sock = ngx.socket.tcp()
2439+
sock:settimeouts(1000, 1000, 1000)
2440+
2441+
local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_PORT)
2442+
if not ok then
2443+
ngx.say("failed to connect: ", err)
2444+
return
2445+
end
2446+
2447+
ngx.say("connected: ", ok)
2448+
2449+
local req = "GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n"
2450+
2451+
local bytes, err = sock:send(req)
2452+
if not bytes then
2453+
ngx.say("failed to send request: ", err)
2454+
return
2455+
end
2456+
2457+
ngx.say("request sent: ", bytes)
2458+
2459+
local reader = sock:receiveuntil("\r\n0\r\n\r\n")
2460+
local data, err = reader()
2461+
if not data then
2462+
ngx.say("failed to receive response body: ", err)
2463+
return
2464+
end
2465+
2466+
ngx.say("received response of ", #data, " bytes")
2467+
2468+
local ok, err = sock:setkeepalive()
2469+
if not ok then
2470+
ngx.say("failed to set reusable: ", err)
2471+
return
2472+
end
2473+
2474+
ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_PORT)
2475+
if not ok then
2476+
ngx.say("failed to connect: ", err)
2477+
return
2478+
end
2479+
2480+
local ok, err = sock:setkeepalive(10, "not a number")
2481+
if not ok then
2482+
ngx.say("failed to set reusable: ", err)
2483+
return
2484+
end
2485+
}
2486+
--- stream_response
2487+
connected: 1
2488+
request sent: 61
2489+
received response of 156 bytes
2490+
--- error_log eval
2491+
qr/\Qbad argument #2 to 'setkeepalive' (number expected, got string)\E/
2492+
--- no_error_log
2493+
[crit]
2494+
--- timeout: 4

0 commit comments

Comments
 (0)