Hello,
I am researcher in software testing from the University of Stuttgart, Germany. We are testing grammar-based fuzzers and have chosen Lua as one of our fuzz targets for our experiments. We found 2 issues in Lua, but one of those seems to be already fixed in recent
versions. Thus, here is the remaining issue we found, which still results in a crash in the current Lua version.
Please excuse that the example looks weird. This is typically the case when generating random test inputs. I wasn't able to trim the input by much.
### System
Lua version: 5.4.5 (c4b71b7ba0dee419b5bda1ec297eca8e42c9f1d2)
System: Rocky Linux release 9.1 (Blue Onyx), 5.14.0-162.18.1.el9_1.x86_64
### Build:
# enable address sanitizer
vim makefile
# change MYCFLAGS and MYLDFLAGS to include '-fsanitize=address'
MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUA_USE_READLINE -fsanitize=address
MYLDFLAGS= $(LOCAL) -Wl,-E -fsanitize=address
# compile lua
make
### Test input (test1.lua):
I included the complete example between three opening and closing backticks (```) like in a Markdown syntax, to distinguish it from the rest of the email. Note that the line breaks seem necessary.
```
return utf8.dump (load (string.dump (function (...) return (((1.8e-2)//(function (table) if ((0.0e-1)//(function (table) if ((0.0e-0)+coroutine) then
coroutine = coroutine.wrap(function (...) ::labelb::
end)
end
end).gsub ([[ ]], "")) then
return (((00)+coroutine)>>"")
end
end).ceil {[( not (1.8e-2))]=(true)})>>function (table) coroutine = coroutine.wrap(function (...) return (((1.8e-2)//(function (table) if ((0.0e-0)~(00)) then
return (((00)+coroutine)>>"")
end
end).ceil {[( not (1.8e-2))]=(true)})>>function (table) coroutine = coroutine.wrap(function (...) ::labelb::
end)
end)
end)
end)
end):gsub ([[ ]], "")), (((00)+coroutine)>>""))
```
### Execution:
./lua test1.lua
### Output with ASAN enabled:
=================================================================
==19331==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000009a0 at pc 0x000000443a15 bp 0x7ffdb4e46000 sp 0x7ffdb4e45ff0
WRITE of size 8 at 0x6020000009a0 thread T0
#0 0x443a14 in loadFunction (/home/rocky/lua/lua+0x443a14)
#1 0x4431eb in loadFunction (/home/rocky/lua/lua+0x4431eb)
#2 0x4431eb in loadFunction (/home/rocky/lua/lua+0x4431eb)
#3 0x444062 in luaU_undump (/home/rocky/lua/lua+0x444062)
#4 0x4173c2 in f_parser (/home/rocky/lua/lua+0x4173c2)
#5 0x4175b9 in luaD_rawrunprotected (/home/rocky/lua/lua+0x4175b9)
#6 0x41bd99 in luaD_pcall (/home/rocky/lua/lua+0x41bd99)
#7 0x41c335 in luaD_protectedparser (/home/rocky/lua/lua+0x41c335)
#8 0x410333 in lua_load (/home/rocky/lua/lua+0x410333)
#9 0x457443 in luaL_loadbufferx (/home/rocky/lua/lua+0x457443)
#10 0x467fb2 in luaB_load (/home/rocky/lua/lua+0x467fb2)
#11 0x41a0ef in luaD_precall (/home/rocky/lua/lua+0x41a0ef)
#12 0x448d0a in luaV_execute (/home/rocky/lua/lua+0x448d0a)
#13 0x41aed6 in luaD_callnoyield (/home/rocky/lua/lua+0x41aed6)
#14 0x4175b9 in luaD_rawrunprotected (/home/rocky/lua/lua+0x4175b9)
#15 0x41bd99 in luaD_pcall (/home/rocky/lua/lua+0x41bd99)
#16 0x40fea4 in lua_pcallk (/home/rocky/lua/lua+0x40fea4)
#17 0x4068b6 in docall (/home/rocky/lua/lua+0x4068b6)
#18 0x407965 in pmain (/home/rocky/lua/lua+0x407965)
#19 0x41a0ef in luaD_precall (/home/rocky/lua/lua+0x41a0ef)
#20 0x41ae9a in luaD_callnoyield (/home/rocky/lua/lua+0x41ae9a)
#21 0x4175b9 in luaD_rawrunprotected (/home/rocky/lua/lua+0x4175b9)
#22 0x41bd99 in luaD_pcall (/home/rocky/lua/lua+0x41bd99)
#23 0x40fea4 in lua_pcallk (/home/rocky/lua/lua+0x40fea4)
#24 0x405aa4 in main (/home/rocky/lua/lua+0x405aa4)
#25 0x7f487669beaf in __libc_start_call_main (/lib64/libc.so.6+0x3feaf)
#26 0x7f487669bf5f in __libc_start_main_alias_1 (/lib64/libc.so.6+0x3ff5f)
#27 0x406174 in _start (/home/rocky/lua/lua+0x406174)
0x6020000009a0 is located 0 bytes to the right of 16-byte region [0x602000000990,0x6020000009a0)
allocated by thread T0 here:
#0 0x7f4876a4cd98 in __interceptor_realloc (/lib64/libasan.so.6+0xb4d98)
#1 0x428611 in luaM_malloc_ (/home/rocky/lua/lua+0x428611)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/rocky/lua/lua+0x443a14) in loadFunction
Shadow bytes around the buggy address:
0x0c047fff80e0: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
0x0c047fff80f0: fa fa fd fd fa fa 00 fa fa fa 00 00 fa fa 00 00
0x0c047fff8100: fa fa 00 00 fa fa 00 00 fa fa 00 fa fa fa 00 00
0x0c047fff8110: fa fa 00 fa fa fa 00 fa fa fa 02 fa fa fa 00 03
0x0c047fff8120: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 fa
=>0x0c047fff8130: fa fa 00 00[fa]fa 00 00 fa fa 00 00 fa fa 00 fa
0x0c047fff8140: fa fa 00 00 fa fa 00 00 fa fa 00 fa fa fa 00 fa
0x0c047fff8150: fa fa 02 fa fa fa 06 fa fa fa 00 00 fa fa 00 00
0x0c047fff8160: fa fa 00 00 fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8170: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==19331==ABORTING
### Output without ASAN enabled:
./lua: test1.lua:28: attempt to perform arithmetic on a table value (global 'coroutine')
stack traceback:
test1.lua:28: in main chunk
[C]: in ?
Expected behavior: No heap buffer overflow.
Best regards,
Maik Betka