heap-buffer-overflow in getobjname

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

heap-buffer-overflow in getobjname

Rui Zhong
Hi,
We found a heap buffer overflow in getobjname function.
Lua version: 
Lua 5.4.0  Copyright (C) 1994-2020 Lua.org, PUC-Rio


See follow PoC:
----------
function
errfunc (  )
setmetatable (
{
}
,
{
    __gc = coroutine
}
)[xpcall
  ( function (  )function crash (  )function
    f ( p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38,
        p39, p40, p41, p42, p43, p44, p45, p46, p48, p49, p50,
        ... ) local a14 end f (  )(  )end for i = 1, 5
    do
    crash (  )end end,
    coroutine.
    wrap ( function (  )xpcall ( test, errfunc ) xpcall ( test, errfunc )
           end ) )]
    = load end coro =
          ( function (  )print ( xpcall ( test, errfunc ) ) end ) (  )
------------

Run this PoC with the original build lua will get
~/lua/lua poc.lua
lua: malloc.c:2394: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.


Asan log:
================================================================
==28107==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000014c at pc 0x00000040e7cb bp 0x7ffd49fcd550 sp 0x7ffd49fcd540
READ of size 4 at 0x60200000014c thread T0
    #0 0x40e7ca in getobjname (/home/yongheng/lua_asan/lua+0x40e7ca)
    #1 0x40ec98 in varinfo (/home/yongheng/lua_asan/lua+0x40ec98)
    #2 0x411575 in luaG_typeerror (/home/yongheng/lua_asan/lua+0x411575)
    #3 0x4138bc in luaD_tryfuncTM (/home/yongheng/lua_asan/lua+0x4138bc)
    #4 0x41480d in luaD_call (/home/yongheng/lua_asan/lua+0x41480d)
    #5 0x415194 in luaD_callnoyield (/home/yongheng/lua_asan/lua+0x415194)
    #6 0x4127d0 in luaD_rawrunprotected (/home/yongheng/lua_asan/lua+0x4127d0)
    #7 0x415d70 in luaD_pcall (/home/yongheng/lua_asan/lua+0x415d70)
    #8 0x41ac34 in GCTM (/home/yongheng/lua_asan/lua+0x41ac34)
    #9 0x41e3de in singlestep (/home/yongheng/lua_asan/lua+0x41e3de)
    #10 0x42026e in luaC_step (/home/yongheng/lua_asan/lua+0x42026e)
   ...
   ...
================================================================

Best,
Yongheng and Rui
Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in getobjname

William Ahern
On Mon, Jul 06, 2020 at 09:58:07PM -0400, Rui Zhong wrote:
> Hi,
> We found a heap buffer overflow in getobjname function.

FWIW, here's the Valgrind report:

==82295== Memcheck, a memory error detector
==82295== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==82295== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==82295== Command: ./src/lua /tmp/poc-getobjname.lua
==82295==
==82295== Invalid read of size 4
==82295==    at 0x113077: findsetreg (ldebug.c:476)
==82295==    by 0x113077: getobjname (ldebug.c:540)
==82295==    by 0x113578: varinfo (ldebug.c:691)
==82295==    by 0x11414A: luaG_typeerror (ldebug.c:700)
==82295==    by 0x114D81: luaD_tryfuncTM (ldo.c:359)
==82295==    by 0x11526B: luaD_call (ldo.c:509)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==    by 0x114842: luaD_rawrunprotected (ldo.c:148)
==82295==    by 0x1158D1: luaD_pcall (ldo.c:749)
==82295==    by 0x11725B: GCTM (lgc.c:852)
==82295==    by 0x1185F7: callallpendingfinalizers (lgc.c:882)
==82295==    by 0x1185F7: finishgencycle (lgc.c:1129)
==82295==    by 0x1185F7: finishgencycle (lgc.c:1124)
==82295==    by 0x118DF8: youngcollection (lgc.c:1165)
==82295==    by 0x118DF8: genstep (lgc.c:1333)
==82295==    by 0x118DF8: luaC_step (lgc.c:1571)
==82295==    by 0x11FE27: luaT_adjustvarargs (ltm.c:243)
==82295==  Address 0x4bae4cc is 4 bytes before a block of size 12 alloc'd
==82295==    at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==82295==    by 0x119174: luaM_realloc_ (lmem.c:166)
==82295==    by 0x1191D4: luaM_saferealloc_ (lmem.c:181)
==82295==    by 0x1192B3: luaM_shrinkvector_ (lmem.c:116)
==82295==    by 0x11B13A: close_func (lparser.c:754)
==82295==    by 0x11BF34: body (lparser.c:998)
==82295==    by 0x11B75D: funcstat (lparser.c:1818)
==82295==    by 0x11B75D: statement (lparser.c:1905)
==82295==    by 0x11BCD2: statlist (lparser.c:796)
==82295==    by 0x11BECD: body (lparser.c:994)
==82295==    by 0x11B75D: funcstat (lparser.c:1818)
==82295==    by 0x11B75D: statement (lparser.c:1905)
==82295==    by 0x11BCD2: statlist (lparser.c:796)
==82295==    by 0x11BECD: body (lparser.c:994)
==82295==
==82295== Invalid write of size 8
==82295==    at 0x11FDC8: luaT_adjustvarargs (ltm.c:248)
==82295==    by 0x12296F: luaV_execute (lvm.c:1795)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==    by 0x114842: luaD_rawrunprotected (ldo.c:148)
==82295==    by 0x1158D1: luaD_pcall (ldo.c:749)
==82295==    by 0x11265D: lua_pcallk (lapi.c:1023)
==82295==    by 0x12BBD3: luaB_xpcall (lbaselib.c:472)
==82295==    by 0x115458: luaD_call (ldo.c:482)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==  Address 0x4cc9300 is 0 bytes after a block of size 1,040 alloc'd
==82295==    at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==82295==    by 0x119174: luaM_realloc_ (lmem.c:166)
==82295==    by 0x1148DF: luaD_reallocstack (ldo.c:187)
==82295==    by 0x114AFF: luaD_shrinkstack (ldo.c:255)
==82295==    by 0x115925: luaD_pcall (ldo.c:757)
==82295==    by 0x11725B: GCTM (lgc.c:852)
==82295==    by 0x1185F7: callallpendingfinalizers (lgc.c:882)
==82295==    by 0x1185F7: finishgencycle (lgc.c:1129)
==82295==    by 0x1185F7: finishgencycle (lgc.c:1124)
==82295==    by 0x118DF8: youngcollection (lgc.c:1165)
==82295==    by 0x118DF8: genstep (lgc.c:1333)
==82295==    by 0x118DF8: luaC_step (lgc.c:1571)
==82295==    by 0x11FE27: luaT_adjustvarargs (ltm.c:243)
==82295==    by 0x12296F: luaV_execute (lvm.c:1795)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==
==82295== Invalid write of size 1
==82295==    at 0x11FDD0: luaT_adjustvarargs (ltm.c:248)
==82295==    by 0x12296F: luaV_execute (lvm.c:1795)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==    by 0x114842: luaD_rawrunprotected (ldo.c:148)
==82295==    by 0x1158D1: luaD_pcall (ldo.c:749)
==82295==    by 0x11265D: lua_pcallk (lapi.c:1023)
==82295==    by 0x12BBD3: luaB_xpcall (lbaselib.c:472)
==82295==    by 0x115458: luaD_call (ldo.c:482)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==  Address 0x4cc9308 is 8 bytes after a block of size 1,040 alloc'd
==82295==    at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==82295==    by 0x119174: luaM_realloc_ (lmem.c:166)
==82295==    by 0x1148DF: luaD_reallocstack (ldo.c:187)
==82295==    by 0x114AFF: luaD_shrinkstack (ldo.c:255)
==82295==    by 0x115925: luaD_pcall (ldo.c:757)
==82295==    by 0x11725B: GCTM (lgc.c:852)
==82295==    by 0x1185F7: callallpendingfinalizers (lgc.c:882)
==82295==    by 0x1185F7: finishgencycle (lgc.c:1129)
==82295==    by 0x1185F7: finishgencycle (lgc.c:1124)
==82295==    by 0x118DF8: youngcollection (lgc.c:1165)
==82295==    by 0x118DF8: genstep (lgc.c:1333)
==82295==    by 0x118DF8: luaC_step (lgc.c:1571)
==82295==    by 0x11FE27: luaT_adjustvarargs (ltm.c:243)
==82295==    by 0x12296F: luaV_execute (lvm.c:1795)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==
==82295== Conditional jump or move depends on uninitialised value(s)
==82295==    at 0x1182D6: sweepgen.isra.0 (lgc.c:1012)
==82295==    by 0x118D41: youngcollection (lgc.c:1148)
==82295==    by 0x118D41: genstep (lgc.c:1333)
==82295==    by 0x118D41: luaC_step (lgc.c:1571)
==82295==    by 0x12C3E0: luaB_cowrap (lcorolib.c:103)
==82295==    by 0x115458: luaD_call (ldo.c:482)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==    by 0x11400E: luaG_errormsg (ldebug.c:765)
==82295==    by 0x1140F7: luaG_runerror (ldebug.c:781)
==82295==    by 0x11D56B: luaE_enterCcall (lstate.c:147)
==82295==    by 0x11D56B: luaE_enterCcall (lstate.c:135)
==82295==    by 0x11D58C: luaE_extendCI (lstate.c:159)
==82295==    by 0x1154B7: luaD_call (ldo.c:489)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==
==82295== Use of uninitialised value of size 8
==82295==    at 0x1182BA: sweepgen.isra.0 (lgc.c:1013)
==82295==    by 0x118D41: youngcollection (lgc.c:1148)
==82295==    by 0x118D41: genstep (lgc.c:1333)
==82295==    by 0x118D41: luaC_step (lgc.c:1571)
==82295==    by 0x12C3E0: luaB_cowrap (lcorolib.c:103)
==82295==    by 0x115458: luaD_call (ldo.c:482)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==    by 0x11400E: luaG_errormsg (ldebug.c:765)
==82295==    by 0x1140F7: luaG_runerror (ldebug.c:781)
==82295==    by 0x11D56B: luaE_enterCcall (lstate.c:147)
==82295==    by 0x11D56B: luaE_enterCcall (lstate.c:135)
==82295==    by 0x11D58C: luaE_extendCI (lstate.c:159)
==82295==    by 0x1154B7: luaD_call (ldo.c:489)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==
==82295== Invalid read of size 1
==82295==    at 0x1182BA: sweepgen.isra.0 (lgc.c:1013)
==82295==    by 0x118D41: youngcollection (lgc.c:1148)
==82295==    by 0x118D41: genstep (lgc.c:1333)
==82295==    by 0x118D41: luaC_step (lgc.c:1571)
==82295==    by 0x12C3E0: luaB_cowrap (lcorolib.c:103)
==82295==    by 0x115458: luaD_call (ldo.c:482)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==    by 0x11400E: luaG_errormsg (ldebug.c:765)
==82295==    by 0x1140F7: luaG_runerror (ldebug.c:781)
==82295==    by 0x11D56B: luaE_enterCcall (lstate.c:147)
==82295==    by 0x11D56B: luaE_enterCcall (lstate.c:135)
==82295==    by 0x11D58C: luaE_extendCI (lstate.c:159)
==82295==    by 0x1154B7: luaD_call (ldo.c:489)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==  Address 0x9 is not stack'd, malloc'd or (recently) free'd
==82295==
==82295==
==82295== Process terminating with default action of signal 11 (SIGSEGV)
==82295==  Access not within mapped region at address 0x9
==82295==    at 0x1182BA: sweepgen.isra.0 (lgc.c:1013)
==82295==    by 0x118D41: youngcollection (lgc.c:1148)
==82295==    by 0x118D41: genstep (lgc.c:1333)
==82295==    by 0x118D41: luaC_step (lgc.c:1571)
==82295==    by 0x12C3E0: luaB_cowrap (lcorolib.c:103)
==82295==    by 0x115458: luaD_call (ldo.c:482)
==82295==    by 0x12260C: luaV_execute (lvm.c:1615)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==    by 0x11400E: luaG_errormsg (ldebug.c:765)
==82295==    by 0x1140F7: luaG_runerror (ldebug.c:781)
==82295==    by 0x11D56B: luaE_enterCcall (lstate.c:147)
==82295==    by 0x11D56B: luaE_enterCcall (lstate.c:135)
==82295==    by 0x11D58C: luaE_extendCI (lstate.c:159)
==82295==    by 0x1154B7: luaD_call (ldo.c:489)
==82295==    by 0x11558A: luaD_callnoyield (ldo.c:526)
==82295==  If you believe this happened as a result of a stack
==82295==  overflow in your program's main thread (unlikely but
==82295==  possible), you can try to increase the size of the
==82295==  main thread stack using the --main-stacksize= flag.
==82295==  The main thread stack size used in this run was 8388608.
==82295==
==82295== HEAP SUMMARY:
==82295==     in use at exit: 166,614 bytes in 1,747 blocks
==82295==   total heap usage: 5,097 allocs, 3,350 frees, 1,024,242 bytes allocated
==82295==
==82295== LEAK SUMMARY:
==82295==    definitely lost: 82 bytes in 1 blocks
==82295==    indirectly lost: 0 bytes in 0 blocks
==82295==      possibly lost: 87,312 bytes in 151 blocks
==82295==    still reachable: 79,220 bytes in 1,595 blocks
==82295==         suppressed: 0 bytes in 0 blocks
==82295== Rerun with --leak-check=full to see details of leaked memory
==82295==
==82295== Use --track-origins=yes to see where uninitialised values come from
==82295== For lists of detected and suppressed errors, rerun with: -s
==82295== ERROR SUMMARY: 25 errors from 6 contexts (suppressed: 0 from 0)
Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in getobjname

Andrew Gierth
In reply to this post by Rui Zhong
>>>>> "Rui" == Rui Zhong <[hidden email]> writes:

 Rui> READ of size 4 at 0x60200000014c thread T0
 Rui>     #0 0x40e7ca in getobjname (/home/yongheng/lua_asan/lua+0x40e7ca)
 Rui>     #1 0x40ec98 in varinfo (/home/yongheng/lua_asan/lua+0x40ec98)
 Rui>     #2 0x411575 in luaG_typeerror (/home/yongheng/lua_asan/lua+0x411575)
 Rui>     #3 0x4138bc in luaD_tryfuncTM (/home/yongheng/lua_asan/lua+0x4138bc)

So the problem here seems to be that the current CallInfo is that of
some Lua function, and where the garbage collector was run before any
savepc() operation (to be precise, from an OP_NEWTABLE opcode). The GC
then tried to call the __gc metamethod of an object, got the "coroutine"
table rather than a function, tried to get a __call metamethod from
that, got nil, and tried to throw an error. Because varinfo thinks that
it was a Lua function that caused the error, it tries to look at the
bytecode to see where the value came from, and reads from before the
start of the bytecode because savedpc still points to the first opcode
(it tries to read the opcode at savedpc-1).

--
Andrew.
Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in getobjname

Dibyendu Majumdar
On Wed, 8 Jul 2020 at 10:58, Andrew Gierth <[hidden email]> wrote:

>
> >>>>> "Rui" == Rui Zhong <[hidden email]> writes:
>
>  Rui> READ of size 4 at 0x60200000014c thread T0
>  Rui>     #0 0x40e7ca in getobjname (/home/yongheng/lua_asan/lua+0x40e7ca)
>  Rui>     #1 0x40ec98 in varinfo (/home/yongheng/lua_asan/lua+0x40ec98)
>  Rui>     #2 0x411575 in luaG_typeerror (/home/yongheng/lua_asan/lua+0x411575)
>  Rui>     #3 0x4138bc in luaD_tryfuncTM (/home/yongheng/lua_asan/lua+0x4138bc)
>
> So the problem here seems to be that the current CallInfo is that of
> some Lua function, and where the garbage collector was run before any
> savepc() operation (to be precise, from an OP_NEWTABLE opcode). The GC
> then tried to call the __gc metamethod of an object, got the "coroutine"
> table rather than a function, tried to get a __call metamethod from
> that, got nil, and tried to throw an error. Because varinfo thinks that
> it was a Lua function that caused the error, it tries to look at the
> bytecode to see where the value came from, and reads from before the
> start of the bytecode because savedpc still points to the first opcode
> (it tries to read the opcode at savedpc-1).
>

Hey Andrew, your debugging skills are amazing!

Regards