SIGABORT in lundump.c on parsing constants in bytecode

61 views
Skip to first unread message

Sergey Bronnikov

unread,
Jun 4, 2025, 8:09:20 AMJun 4
to lua-l
Hello,

an assertion is triggered on execution of a Lua chunk below:

local chars = { 0x1b, 0x4c, 0x75, 0x61, 0x55, 0x00,
0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a, 0x04, 0x88, 0xa9,
0xff, 0xff, 0x04, 0x78, 0x56, 0x34, 0x12, 0x08, 0x88,
0xa9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x28, 0x77, 0xc0, 0x00, 0x19,
0x93, 0x0d, 0x0a, 0x1a, 0x0a, 0x04, 0x88, 0xa9, 0xff,
0xff, 0x04, 0x78, 0x56, 0x34, 0x12, 0x08, 0x88, 0xa9,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00,
0x00, 0x00, 0x2f, 0x2e, 0x2e, 0x00 }

local bc = ""
for _, ch in ipairs(chars) do
  bc = bc .. string.char(ch)
end

load(bc, "", "b")

Reproduced on the latest version of Lua (c15543b9afa31ab5dc564511ae11acd808405e8f) that built with enabled macro -DLUAI_ASSERT. Honestly, I don't think it is a real bug, just a protection against malicious bytecode.

--- a/makefile
+++ b/makefile
@@ -71,7 +71,7 @@ LOCAL = $(TESTS) $(CWARNS)
 # To enable Linux goodies, -DLUA_USE_LINUX
 # For C89, "-std=c89 -DLUA_USE_C89"
 # Note that Linux/Posix options are not compatible with C89
-MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX
+MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUAI_ASSERT
 MYLDFLAGS= $(LOCAL) -Wl,-E
 MYLIBS= -ldl
 
Backtrace:

lua: lundump.c:237: loadConstants: Assertion `0' failed.                
                                                                                                                                                             
Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:44                                                  
warning: 44     ./nptl/pthread_kill.c: No such file or directory                                                                                              
(gdb) bt                                                                                                                                                      
#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:44                                
#1  __pthread_kill_internal (signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:78                                                    
#2  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3  0x00007ffff744527e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26                                                                      
#4  0x00007ffff74288ff in __GI_abort () at ./stdlib/abort.c:79
#5  0x00007ffff742881b in __assert_fail_base (fmt=0x7ffff75d01e8 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x55555570071b "0",
    file=file@entry=0x555555700173 "lundump.c", line=line@entry=237, function=function@entry=0x555555709868 <__PRETTY_FUNCTION__.2> "loadConstants")
    at ./assert/assert.c:96                                                    
#6  0x00007ffff743b517 in __assert_fail (assertion=assertion@entry=0x55555570071b "0", file=file@entry=0x555555700173 "lundump.c", line=line@entry=237,    
    function=function@entry=0x555555709868 <__PRETTY_FUNCTION__.2> "loadConstants") at ./assert/assert.c:105                                              
#7  0x00005555556970af in loadConstants (f=<optimized out>, S=<optimized out>) at lundump.c:237            
#8  loadFunction (S=S@entry=0x7fffffffc5c0, f=0x5555557bdaa0) at lundump.c:331                                                                                
#9  0x000055555569886e in luaU_undump (L=L@entry=0x5555557b6838, Z=<optimized out>, name=<optimized out>, fixed=<optimized out>) at lundump.c:413
#10 0x000055555563ca74 in f_parser (L=L@entry=0x5555557b6838, ud=ud@entry=0x7fffffffc810) at ldo.c:1091
#11 0x000055555563ced8 in luaD_rawrunprotected (L=L@entry=0x5555557b6838, f=f@entry=0x55555563c910 <f_parser>, ud=0x7fffffffc810) at ldo.c:148            
#12 0x0000555555646d1e in luaD_pcall (L=L@entry=0x5555557b6838, func=func@entry=0x55555563c910 <f_parser>, u=u@entry=0x7fffffffc810, old_top=208,
    ef=<optimized out>) at ldo.c:1045                                          
#13 0x0000555555647063 in luaD_protectedparser (L=L@entry=0x5555557b6838, z=z@entry=0x7fffffffc8b0, name=name@entry=0x5555557bdfb8 "",
#14 0x00005555556272dd in lua_load (L=L@entry=0x5555557b6838, reader=reader@entry=0x5555556cdab0 <getS>, data=data@entry=0x7fffffffc920,
    chunkname=0x5555557bdfb8 "", mode=mode@entry=0x5555557be588 "b") at lapi.c:1121
#15 0x00005555556d0060 in luaL_loadbufferx (L=L@entry=0x5555557b6838, buff=buff@entry=0x5555557bfad0 "\033LuaU", size=<optimized out>, name=<optimized out>,
    mode=mode@entry=0x5555557be588 "b") at lauxlib.c:872
#16 0x00005555556ea53b in luaB_load (L=0x5555557b6838) at lbaselib.c:404
#17 0x0000555555641258 in precallC (L=L@entry=0x5555557b6838, func=func@entry=0x5555557bc910, status=status@entry=1, f=0x5555556ea4c0 <luaB_load>)
    at ldo.c:612
#18 0x0000555555644272 in luaD_precall (L=L@entry=0x5555557b6838, func=<optimized out>, func@entry=0x5555557bc910, nresults=nresults@entry=0) at ldo.c:681
#19 0x00005555556a796d in luaV_execute (L=L@entry=0x5555557b6838, ci=<optimized out>) at lvm.c:1696
#20 0x0000555555644d93 in ccall (L=0x5555557b6838, func=<optimized out>, nResults=-1, inc=65537) at ldo.c:723
#21 0x000055555563ced8 in luaD_rawrunprotected (L=L@entry=0x5555557b6838, f=f@entry=0x555555613220 <f_call>, ud=0x7fffffffcce0) at ldo.c:148
#22 0x0000555555646d1e in luaD_pcall (L=L@entry=0x5555557b6838, func=func@entry=0x555555613220 <f_call>, u=u@entry=0x7fffffffcce0, old_top=80,
    ef=<optimized out>) at ldo.c:1045
#23 0x0000555555626882 in lua_pcallk (L=L@entry=0x5555557b6838, nargs=nargs@entry=0, nresults=nresults@entry=-1, errfunc=errfunc@entry=3, ctx=ctx@entry=0,
    k=k@entry=0x0) at lapi.c:1091
#24 0x000055555560c89d in docall (L=L@entry=0x5555557b6838, narg=narg@entry=0, nres=nres@entry=-1) at lua.c:162
#25 0x000055555560df40 in handle_script (argv=<optimized out>, L=0x5555557b6838) at lua.c:266
#26 pmain (L=0x5555557b6838) at lua.c:722
#27 0x0000555555641258 in precallC (L=L@entry=0x5555557b6838, func=func@entry=0x5555557b6920, status=status@entry=2, f=0x55555560cfb0 <pmain>) at ldo.c:612
#28 0x0000555555644272 in luaD_precall (L=L@entry=0x5555557b6838, func=<optimized out>, func@entry=0x5555557b6920, nresults=nresults@entry=1) at ldo.c:681
#29 0x0000555555644d4d in ccall (L=0x5555557b6838, func=0x5555557b6920, nResults=1, inc=65537) at ldo.c:721
#30 0x000055555563ced8 in luaD_rawrunprotected (L=L@entry=0x5555557b6838, f=f@entry=0x555555613220 <f_call>, ud=0x7fffffffd110) at ldo.c:148
#31 0x0000555555646d1e in luaD_pcall (L=L@entry=0x5555557b6838, func=func@entry=0x555555613220 <f_call>, u=u@entry=0x7fffffffd110, old_top=16,
    ef=<optimized out>) at ldo.c:1045
#32 0x0000555555626882 in lua_pcallk (L=L@entry=0x5555557b6838, nargs=nargs@entry=2, nresults=nresults@entry=1, errfunc=errfunc@entry=0, ctx=ctx@entry=0,
    k=k@entry=0x0) at lapi.c:1091
#33 0x000055555560c21b in main (argc=2, argv=0x7fffffffd298) at lua.c:750
(gdb)

Initially reported by Github user gal1ium [1].


Sergey

Sainan

unread,
Jun 4, 2025, 9:08:45 AMJun 4
to lu...@googlegroups.com
> protection against malicious bytecode

The only protection against malicious bytecode is not accepting bytecode that you think could be malicious.

-- Sainan
Reply all
Reply to author
Forward
0 new messages