|
Jinwei Dong wrote: > I did some simple debugging by inserting 'printf()' into the following call > chain: > ----------------- > luaG_runerror()->luaG_errormsg()->ccall()...luaG_runerror()->luaG_errormsg()->CRASH! > ----------------- > > And got this: > ----------------- > [luaG_runerror()] attempt to call a number value > [luaG_errormsg()] L->errfunc: 0xa0 > [luaG_errormsg()] L->top: 0x5555555979e0 > [ccall()] L->nCcalls: 0x50004 LUAI_MAXCCALLS: 0xc8 > [luaG_runerror()] attempt to index a nil value (global 't') > [luaG_errormsg()] L->errfunc: 0xa0 > [luaG_errormsg()] L->top: 0x555555597ab0 > [ccall()] L->nCcalls: 0x60005 LUAI_MAXCCALLS: 0xc8 > [luaG_runerror()] attempt to index a nil value (global 't') > [luaG_errormsg()] L->errfunc: 0xa0 > [luaG_errormsg()] L->top: 0x555555597b80 > [ccall()] L->nCcalls: 0x70006 LUAI_MAXCCALLS: 0xc8 > ...... > [luaG_runerror()] attempt to index a nil value (global 't') > [luaG_errormsg()] L->errfunc: 0xa0 > [luaG_errormsg()] L->top: 0x5555555b35f0 > [ccall()] L->nCcalls: 0xc900c8 LUAI_MAXCCALLS: 0xc8 > [luaG_runerror()] C stack overflow > [luaG_errormsg()] L->errfunc: 0xa0 > [luaG_errormsg()] L->top: 0x5555555b3620 > ----------------- > > Then I do the following analysis (as you said before): > > When the first error that 'attempt to call a number value' occour, program will > run into error handling function provide by 'xpcall'. At this point a second error > that 'attempt to index a nil value' occurred. Because this error occurs in an > error handling function, a recursive error handling is triggered. > > Everytime 'ccall' was called, it will check `l_unlikely(getCcalls(L) >= > LUAI_MAXCCALLS` which makes sure that the stack buffer is not overflowed. Until this > condition is met, the program will call the 'luaE_checkcstack' function. This > function will execute the following statement: `luaG_runerror(L, "C stack > overflow");`. And program goes into luaG_runerror again... > > Bad things happen: 'luaG_runerror()->luaG_errormsg()' will push some value to > lua stack (actually the tail of the heap memory allocated by glibc) but will not grow the > stack. Eventually this overflow overwrites zero value to the 'prev_inuse' field of > the 'prevsize' of the next heap chunk. This will cause 'double free' crash > report of glibc (not the real double free). > > This is the mem status before the overwrite: > ---------------- > pwndbg> x/10gx 0x5555555b3620-0x10 > 0x5555555b3610: 0x000055555559eea0 0x0000000000000044 <- tail of old stack (heap > chunk) > 0x5555555b3620: 0x0000000000000000 0x0000000000000051 <- next heap chunk > 0x5555555b3630: 0x00005555555a8c60 0x4b88da7300001014 > 0x5555555b3640: 0x0000000000000029 0x2074706d65747461 > 0x5555555b3650: 0x7865646e69206f74 0x76206c696e206120 > ---------------- > > This is the mem status after the overwrite: > ---------------- > 0x5555555b3610: 0x000055555559eea0 0x0000000000000044 <- tail of old stack (heap > chunk) > 0x5555555b3620: 0x000055555559eea0 0x0000000000000044 <- next heap chunk (damaged) > 0x5555555b3630: 0x00005555555a8c60 0x4b88da7300001014 > 0x5555555b3640: 0x0000000000000029 0x2074706d65747461 > 0x5555555b3650: 0x7865646e69206f74 0x76206c696e206120 > ---------------- > > This is my brief analysis of the bugs. Does anyone have any good ideas on how to fix issues like this? In fact I'm curious how the developers would treat these weird little bugs. |