Nmap Development mailing list archives

Re: Possible script deadlock while testing in nse-lua-merge


From: David Fifield <david () bamsoftware com>
Date: Tue, 24 Mar 2009 22:16:34 -0600

On Tue, Mar 24, 2009 at 08:50:35PM -0600, Patrick Donnelly wrote:
On Tue, Mar 24, 2009 at 7:10 PM, David Fifield <david () bamsoftware com> wrote:
Can you explain more fully the nature of this problem?

It could be a variety of problems that prevent scripts from ever
obtaining a socket connection. I think the most probable is that some
script is holding on to references of a socket even after finishing
execution.

What is holding the reference to the socket? Is the script thread
garbage collected after it terminates? Maybe we have to add a call to
the garbage collector in the Lua snippet in luaopen_nsock?

Can you explain why that is necessary, and why leaving the values on the
stack, as is done now, doesn't work?

nse-lua uses the coroutine library to obtain any yielded values from
the stack. Lua's coroutine library will actually consume these values
(remove them from the stack) and then move them onto the callers
thread. For example:

  lua_pushboolean(L, false);
  lua_pushstring(L, "some error message");
  lua_yield(L, 2);

This code will yield the two values. If another thread were to access
this yielded thread in C, you would see a stack size of 2 and the two
values, false and "some error message". Before, NSE (in C++) would
leave those values on the stack. In fact, NSE would ignore any yielded
values as it only cared when a script finished.

Now, however, nse-lua uses the coroutine library which moves those two
values onto the main thread using lua_xmove, the relevant lines in the
coroutine library (lbaselib.c) are:

  status = lua_resume(co, narg);
  if (status == 0 || status == LUA_YIELD) {
    int nres = lua_gettop(co);
    if (!lua_checkstack(L, nres + 1))
      luaL_error(L, "too many results to resume");
    lua_xmove(co, L, nres);  /* move yielded values */
    return nres;
  }

The nsock library would rely on previous behavior that the yielded
values were always left on the stack. Specifically, the receive_buf
function would actually yield its own arguments so the callback would
have access to them. Because these values are now all consumed by the
coroutine library, another method of saving the arguments had to be
used. Without spending too much time worrying about the cleanest way
to make this possible, I just used indices in the registry (luaL_ref
and luaL_unref). As I said previously, I hope to fix this in the
future.

That's a very good explanation. I agree that the quick fix of rbuf_args
is appropriate for now.

David Fifield

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


Current thread: