Skip to content

Commit 046e9b3

Browse files
Mike PallBuristan
authored andcommitted
Fix error generation in load*.
Reported by Sergey Kaplun. (cherry picked from commit e76bb50) The chunkname pointer to the "@filename" is put on the Lua stack before the `lua_loadx()` and is removed right before the next `lua_pushfstring()` in case of the error. If the GC takes the step right at this moment inside `lua_pushfstring()` the string may be collected, and the next read from this `chunkname + 1` is from the deallocated memory. This patch fixes this by using the source string (or the constant one) instead. Sergey Kaplun: * added the description and the test for the problem Part of tarantool/tarantool#11278 Reviewed-by: Sergey Bronnikov <[email protected]> Signed-off-by: Sergey Kaplun <[email protected]>
1 parent 9794698 commit 046e9b3

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

src/lj_load.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ LUALIB_API int luaL_loadfilex(lua_State *L, const char *filename,
108108
copyTV(L, L->top-1, L->top);
109109
}
110110
if (err) {
111+
const char *fname = filename ? filename : "stdin";
111112
L->top--;
112-
lua_pushfstring(L, "cannot read %s: %s", chunkname+1, strerror(err));
113+
lua_pushfstring(L, "cannot read %s: %s", fname, strerror(err));
113114
return LUA_ERRFILE;
114115
}
115116
return status;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
local tap = require('tap')
2+
3+
-- Test file to demonstrate LuaJIT use-after-free in case of the
4+
-- error in `loadfile()`.
5+
-- See also: https://github.com/LuaJIT/LuaJIT/issues/1353.
6+
local test = tap.test('lj-1353-loadfile-err-use-after-free'):skipcond({
7+
['Too many GC objects on start'] = _TARANTOOL,
8+
})
9+
10+
test:plan(1)
11+
12+
-- Determine the GC step size to finish the GC cycle in one step.
13+
local full_step = 1
14+
while true do
15+
collectgarbage('collect')
16+
collectgarbage('setpause', 0)
17+
collectgarbage('setstepmul', full_step)
18+
if collectgarbage('step') then break end
19+
full_step = full_step + 1
20+
end
21+
22+
-- Check all possible GC step sizes.
23+
for i = 1, full_step do
24+
collectgarbage('collect')
25+
collectgarbage('setpause', 0)
26+
collectgarbage('setstepmul', i)
27+
repeat
28+
-- On Linux-like systems this always returns `nil`, with the
29+
-- error: "cannot read .: Is a directory"
30+
-- The string for the filename "@." may be collected during
31+
-- the call, and later the pointer to the "." from that string
32+
-- is used after the string is free.
33+
loadfile('.')
34+
until collectgarbage('step')
35+
end
36+
37+
test:ok(true, 'no use-after-free error')
38+
39+
test:done(true)

0 commit comments

Comments
 (0)