On Mon, Mar 2, 2015 at 10:01 AM, Coda Highland <chighland@xxxxxxxxx> wrote: > On Mon, Mar 2, 2015 at 9:59 AM, Coda Highland <chighland@xxxxxxxxx> wrote: >> On Mon, Mar 2, 2015 at 9:57 AM, Mike Pall <mike-1503@xxxxxxxxxx> wrote: >>> Alexander Nasonov wrote: >>>> But it's not easy to fool afl. These are the two programs it found: >>>> >>>> s="";s=load"adstrs=loadstring(s);wstring(s)ing(s);wstring(s)";s=loadstring(s);wstring(s);while >>>> s do s=s(s) end >>>> s="";s=load"adstrins=loadstring(s);wstrg(s);wstring(s)";s=loadstring(s);wstring(s);while >>>> s do s=s(s) end >>>> >>>> both crash LuaJIT 2.0. >>> >>> This doesn't crash for me. Neither in 2.0.3 nor in 2.0 git, nor in >>> 2.1 git. Neither when compiled as x86 nor as x64. >>> >>> It complains about "attempt to call global 'wstring' (a nil value)". >>> But that's expected, since 'wstring' is not defined. >>> >>> --Mike >>> >> >> It crashes for me in 2.0.3. I took some time to reduce the test case >> to something a lot simpler. >> >> $ uname -a >> Darwin mac-pro 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 >> 16:26:45 PDT 2012; root:xnu-1699.32.7~1/RELEASE_I386 i386 >> >> $ luajit >> LuaJIT 2.0.3 -- Copyright (C) 2005-2014 Mike Pall. http://luajit.org/ >> JIT: ON CMOV SSE2 SSE3 fold cse dce fwd dse narrow loop abc sink fuse >>> s = load"load(s)" >>> load(s) >> Segmentation fault: 11 >> >> /s/ Adam > > For context: > > $ lua > Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio >> s = load"load(s)" > stdin:1: bad argument #1 to 'load' (function expected, got string) > stack traceback: > [C]: in function 'load' > stdin:1: in main chunk > [C]: ? > > /s/ Adam Fixed the 5.2-ism: $ lua Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio > s = loadstring"load(s)" > load(s) Here, it just hangs instead of crashing. I'm guessing PUC-Rio Lua is handling the stack differently, but it's still a DoS from untrusted code. And thinking about it this way reveals the issue: This isn't a bug, or at least, it's not a bug you can do anything about without making Mr. Turing very upset. Let's walk through it: The first line, s = loadstring"load(s)", is equivalent to: function s() load(s) end (And note that it still crashes if you define it this way instead of using loadstring.) The second line, load(s), uses the function s as a reader that's supposed to return incremental parts of the input file. However, s just calls load(s)... which calls s... which calls load(s)... You're just overflowing the stack with infinite recursion. /s/ Adam