Handle immediate callback before thread yields

Nsock makes no guarantees that it will not call the callback for various
functions before returning, so we have to check for that and not assert
it. Fixes #3250. Fixes #3206.
This commit is contained in:
dmiller 2026-05-05 20:58:55 +00:00
parent 36e2bf126d
commit 9458beda4c
2 changed files with 46 additions and 17 deletions

View file

@ -1,5 +1,9 @@
#Nmap Changelog ($Id$); -*-text-*-
o [NSE][GH#3250][GH#3206] Fix assertion failures in cases where connect or send
returns immediately with a status other than ERROR, e.g. TIMEOUT or CANCELED.
[Daniel Miller]
o Fix a crash when writing long CPE strings to output. Reported by Harshit
Gupta. [Daniel Miller]

View file

@ -359,15 +359,23 @@ static void callback (nsock_pool nsp, nsock_event nse, void *ud)
if (nse_status(nse) == NSE_STATUS_KILL)
return;
assert(nse_type(nse) != NSE_TYPE_READ);
if (lua_status(L) == LUA_OK && nse_status(nse) == NSE_STATUS_ERROR) {
// Sometimes Nsock fails immediately and callback is called before
// l_connect has a chance to yield. We'll use nu->action to signal
// l_connect to return an error instead of yielding.
// http://seclists.org/nmap-dev/2016/q1/201
trace(nse_iod(nse), nu->action, nu->direction);
trace(nse_iod(nse), nu->action, nu->direction);
if (lua_status(L) == LUA_OK) {
// Sometimes an operation finishes immediately and Nsock calls the callback
// before the caller has a chance to yield. We'll use nu->action to signal
// the caller to return instead of yielding.
nu->action = NU_ACTION_IMMEDIATE;
if (nse_status(nse) == NSE_STATUS_SUCCESS) {
lua_pushboolean(L, true);
}
else {
lua_pushboolean(L, false);
lua_pushstring(L, nse_status2str(nse_status(nse)));
}
return;
}
assert(lua_status(L) == LUA_YIELD);
switch (nse_type(nse)) {
case NSE_TYPE_CONNECT:
case NSE_TYPE_CONNECT_SSL:
@ -378,8 +386,6 @@ static void callback (nsock_pool nsp, nsock_event nse, void *ud)
default:
break;
}
assert(lua_status(L) == LUA_YIELD);
trace(nse_iod(nse), nu->action, nu->direction);
status(L, nse_status(nse));
}
@ -468,9 +474,15 @@ static int l_reconnect_ssl (lua_State *L)
return nseU_safeerror(L, "sorry, you don't have OpenSSL");
#endif
int oldtop = lua_gettop(L);
nu->action = "SSL RECONNECT";
nsock_reconnect_ssl(nsp, nu->nsiod, callback, nu->timeout,
nu, nu->ssl_session);
if (nu->action == NU_ACTION_IMMEDIATE) {
// Immediate return
return lua_gettop(L) - oldtop;
}
return yield(L, nu, "SSL RECONNECT", TO, 0, NULL);
}
@ -553,6 +565,7 @@ static int connect (lua_State *L, int status, lua_KContext ctx)
nu->action = "PRECONNECT";
nu->direction = TO;
int oldtop = lua_gettop(L);
switch (what)
{
case TCP:
@ -579,8 +592,8 @@ static int connect (lua_State *L, int status, lua_KContext ctx)
freeaddrinfo(dest);
if (nu->action == NU_ACTION_IMMEDIATE) {
// Immediate error
return nseU_safeerror(L, nse_status2str(NSE_STATUS_ERROR));
// Immediate return
return lua_gettop(L) - oldtop;
}
return yield(L, nu, "CONNECT", TO, 0, NULL);
}
@ -598,10 +611,12 @@ static int l_send (lua_State *L)
size_t size;
const char *string = luaL_checklstring(L, 2, &size);
trace(nu->nsiod, hexify((unsigned char *) string, size).c_str(), TO);
int oldtop = lua_gettop(L);
nu->action = "SEND";
nsock_write(nsp, nu->nsiod, callback, nu->timeout, nu, string, size);
if (nu->action == NU_ACTION_IMMEDIATE) {
// Immediate error
return nseU_safeerror(L, nse_status2str(NSE_STATUS_ERROR));
// Immediate return
return lua_gettop(L) - oldtop;
}
return yield(L, nu, "SEND", TO, 0, NULL);
}
@ -626,9 +641,15 @@ static int l_sendto (lua_State *L)
if (dest == NULL)
return nseU_safeerror(L, "getaddrinfo returned success but no addresses");
nsock_sendto(nsp, nu->nsiod, callback, nu->timeout, nu, dest->ai_addr, dest->ai_addrlen, port, string, size);
trace(nu->nsiod, hexify((unsigned char *) string, size).c_str(), TO);
int oldtop = lua_gettop(L);
nu->action = "SENDTO";
nsock_sendto(nsp, nu->nsiod, callback, nu->timeout, nu, dest->ai_addr, dest->ai_addrlen, port, string, size);
freeaddrinfo(dest);
if (nu->action == NU_ACTION_IMMEDIATE) {
// Immediate return
return lua_gettop(L) - oldtop;
}
return yield(L, nu, "SEND", TO, 0, NULL);
}
@ -652,11 +673,11 @@ static void receive_callback (nsock_pool nsp, nsock_event nse, void *udata)
nu->action = NU_ACTION_IMMEDIATE;
return;
}
else if (lua_status(L) == LUA_OK && nse_status(nse) == NSE_STATUS_EOF) {
else if (lua_status(L) == LUA_OK) {
// since r39028, read event can fail immediately if the socket is EOF.
trace(nse_iod(nse), nu->action, "EOF");
lua_pushnil(L);
lua_pushliteral(L, "EOF");
trace(nse_iod(nse), nse_status2str(nse_status(nse)), FROM);
lua_pushboolean(L, false);
lua_pushstring(L, nse_status2str(nse_status(nse)));
nu->action = NU_ACTION_IMMEDIATE;
return;
}
@ -670,6 +691,7 @@ static int l_receive (lua_State *L)
nse_nsock_udata *nu = check_nsock_udata(L, 1, true);
NSOCK_UDATA_ENSURE_OPEN(L, nu);
int oldtop = lua_gettop(L);
nu->action = "RECEIVE";
nsock_read(nsp, nu->nsiod, receive_callback, nu->timeout, nu);
if (nu->action == NU_ACTION_IMMEDIATE) {
// Immediate return
@ -684,6 +706,7 @@ static int l_receive_lines (lua_State *L)
nse_nsock_udata *nu = check_nsock_udata(L, 1, true);
NSOCK_UDATA_ENSURE_OPEN(L, nu);
int oldtop = lua_gettop(L);
nu->action = "RECEIVE LINES";
nsock_readlines(nsp, nu->nsiod, receive_callback, nu->timeout, nu,
luaL_checkinteger(L, 2));
if (nu->action == NU_ACTION_IMMEDIATE) {
@ -699,6 +722,7 @@ static int l_receive_bytes (lua_State *L)
nse_nsock_udata *nu = check_nsock_udata(L, 1, true);
NSOCK_UDATA_ENSURE_OPEN(L, nu);
int oldtop = lua_gettop(L);
nu->action = "RECEIVE BYTES";
nsock_readbytes(nsp, nu->nsiod, receive_callback, nu->timeout, nu,
luaL_checkinteger(L, 2));
if (nu->action == NU_ACTION_IMMEDIATE) {
@ -769,6 +793,7 @@ static int receive_buf (lua_State *L, int status, lua_KContext ctx)
{
lua_pop(L, 2); /* pop 2 results */
int oldtop = lua_gettop(L);
nu->action = "RECEIVE BUF";
nsock_read(nsp, nu->nsiod, receive_callback, nu->timeout, nu);
if (nu->action == NU_ACTION_IMMEDIATE) {
// Immediate return