Nmap Development mailing list archives

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


From: Patrick Donnelly <batrick () batbytes com>
Date: Tue, 24 Mar 2009 20:50:35 -0600

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.

In the
nse-lua-merge branch you have added to the Nsock userdata an array that
indirectly holds the arguments to receive_buf:

struct l_nsock_udata {
       ...
       int rbuf_args[3]; /* indices in lua registry for receive_buf args */
       ...
};

In the nse-lua branch you have fuller support for that kind of thing.

nse-lua has the same problem, I just have not corrected it yet in that
branch. As I noted privately in e-mail with you, it has escaped notice
because receive_buf is rarely used.

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.

-- 
-Patrick Donnelly

"One of the lessons of history is that nothing is often a good thing
to do and always a clever thing to say."

-Will Durant

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

Current thread: