Nmap Development mailing list archives

Re: [NSE] assertion failure in stdnse.sleep()


From: Henri Doreau <henri.doreau () gmail com>
Date: Tue, 6 Nov 2012 13:43:36 +0100

2012/10/17 Patrick Donnelly <batrick () batbytes com>

Hi David,

On Wed, Oct 17, 2012 at 4:59 PM, David Fifield <david () bamsoftware com>
wrote:
One is that
calling sleep or another yielding function doesn't seem to work from an
exception handler:

local stdnse = require('stdnse')
prerule = function() return true end
action = function()
  local catch = function() stdnse.sleep(20) end
  local try = nmap.new_try(catch)
  try(false)
end

attempt to yield across metamethod/C-call boundary
stack traceback:
        [C]: in function 'sleep'
        a.nse:4: in function <a.nse:4>
        [C]: in function 'try'
        a.nse:6: in function <a.nse:3>
        (...tail calls...)

I'm confused by this error because I thought that "yield across
metamethod/C-call boundary" wasn't a thing anymore with Lua 5.2.

It still exists. A regular lua_call (in C [1]) does not allow
coroutine yields to cross the call boundary. We still use lua_call in
new_try_finalize.

To contrast, many call paths in Lua have been adapted so that you
never see this C boundary error anymore, e.g. pcall [2] or dofile [3].
These functions use lua_callk or lua_pcallk. Lua allows yields across
these functions because the caller passes a continuation function to
Lua. This enables Lua to restart the function when the coroutine is
resumed again. See for example, the continuation function for pcall
[4]. Continuations are explained in the manual [5].

I wrote a quick patch (untested) which should correct the problem,
attached.

[1] http://www.lua.org/manual/5.2/manual.html#lua_call
[2] http://www.lua.org/source/5.2/lbaselib.c.html#luaB_pcall
[3] http://www.lua.org/source/5.2/lbaselib.c.html#luaB_dofile
[4] http://www.lua.org/source/5.2/lbaselib.c.html#pcallcont
[5] http://www.lua.org/manual/5.2/manual.html#4.7

I thought about using nse_destructor to have l_sleep register a
destructor that cancels the timer event; hopefully this happens before
the thread is freed.

Destructors are run before the thread is freed.

For socket functions, they are able to associate the thread with the
socket userdatum to ensure the thread is never collected before the
socket userdatum is collected. [This is why it's not necessary to
register a destructor for socket methods as, if the thread no longer
exists, the nse_restore function will silently fail. This could happen
if NSE throws out a timed out script and the nsock callback tries to
nse_restore the thread.] Unfortunately, we don't have that convenience
for the sleep function.

I guess the appropriate way to deal with this unique problem is both
making try/catch C continuation compatible (with the patch attached)
and
adding a destructor to sleep so this situation can't happen again.

--
- Patrick Donnelly



Hi,

what's the status concerning this issue?

With your patch I can still reproduce a similar crash by doing the
following (strange) steps:

1: Patch a random script to make it sleep for a while
Index: scripts/ssh-hostkey.nse
===================================================================
--- scripts/ssh-hostkey.nse     (revision 30204)
+++ scripts/ssh-hostkey.nse     (working copy)
@@ -127,6 +127,8 @@
   local format = nmap.registry.args.ssh_hostkey or "hex"
   local all_formats = format:find( 'all', 1, true )

+  stdnse.sleep(3)
+
   key = ssh1.fetch_host_key( host, port )
   if key then table.insert( keys, key ) end

2: Run
./nmap --script ssh-hostkey --host-timeout 2s localhost
Starting Nmap 6.02 ( http://nmap.org )
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00026s latency).
Skipping host localhost (127.0.0.1) due to host timeout
Nmap done: 1 IP address (1 host up) scanned in 2.19 seconds
nmap: nse_nsock.cc:710: void sleep_callback(void*, void*, void*): Assertion
`lua_status(L) == 1' failed.


Also, if I run: ./nmap --script ssh-hostkey --host-timeout 2s
--max-hostgroup=1 localhost localhost
(note that localhost is specified twice here) I get:
Starting Nmap 6.02 ( http://nmap.org )
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00026s latency).
Skipping host localhost (127.0.0.1) due to host timeout
nmap: nse_nsock.cc:710: void sleep_callback(void*, void*, void*): Assertion
`lua_status(L) == 1' failed.
Aborted

Although I'd have expected the crash to happen for the first hostgroup
too... I'm getting very confused with this issue.

Regards

-- 
Henri
_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/


Current thread: