lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I was using a lua interpreter + LuaSocket as a sort of "rich man's" netcat over the weekend. Doing various socket stuff repetitiously by hand meant I occasionally got things in the wrong order, like this...

s = coresock.tcp()
s:connect("lua.org",80)
s:close()
m,e = s:receive(1024) -- same with receiving "*l" = m,e
nil     closed

...or like this...

s = coresock.tcp()
s:connect("lua.org",80)
s:close()
m,e = s:receive("*a")
Segmentation fault
user@my.example:~$

A very quick glance in the debugger suggests that the receive() method is called, into recvall() and into this:

static int buffer_get(p_buffer buf, const char **data, size_t *count) {
    int err = IO_DONE;
    p_io io = buf->io;
    p_timeout tm = buf->tm;
    if (buffer_isempty(buf)) {
        size_t got;
        err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
        buf->first = 0;
        buf->last = got;
    }
    *count = buf->last - buf->first;
    *data = buf->data + buf->first;
    return err;
}

In my build (debug and release), "got" is not initialised to zero and since io->recv returns immediately with IO_CLOSED withit writing into &got, it ends up with the value [large positive int], so on return to:

static int recvall(p_buffer buf, luaL_Buffer *b) {
    int err = IO_DONE;
    while (err == IO_DONE) {
        const char *data; size_t count;
        err = buffer_get(buf, &data, &count);
        luaL_addlstring(b, data, count);
        buffer_skip(buf, count);
    }
    if (err == IO_CLOSED) return IO_DONE;
    else return err;
}

the luaL_addlstring() causes a buffer overflow.

Changing "size_t got" to "size_t *got = 0" prevents this problem, but introduces another: when calling recvall() (which receive("*a") does but receive(1024) and receive("*l") do not), the error IO_CLOSED is mapped back to IO_DONE, so that the in above Lua code, you can't ever check, from the return values of s:receive("*a"), that the socket was closed when you tried to read from it -- is this correct behaviour for "*a" ?