heap-buffer-overflow in luaD_pretailcall

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

heap-buffer-overflow in luaD_pretailcall

Rui Zhong
Hi,

We found a heap-buffer-overflow in Lua (Lua 5.4.0  Copyright (C) 1994-2020 Lua.org, PUC-Rio)
Try following PoC
-------------------------
function
crash (  )
do
    function errfunc (  ) end coro =
        function (  )print ( xpcall ( test, errfunc ) )
        print ( setmetatable ( { }
                               , { __gc = function (  )asserty = k + 1 end }
                             ) )end coro (  )return load ( string.
                                     dump ( function
                                            ( p8, p9, p10, p11, p12, p13,
                                                    p14, p15, p16, p17, p18,
                                                    p19, p20, p21, p22, p23,
                                                    p24, p25, p26, p5, p6, p7,
                                                    p8, p9, p10, p11, p12, p13,
                                                    p14, p15, p16, p17, p18,
                                                    p19 ) end ) ) (  )end end
                                     for i
                                     = 1, 5
                                       do
                                           crash (  )end
-------------------------
Compile Lua with Address sanitizer and run above PoC.
Asan log:
================================================================
==5190==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6160000017e8 at pc 0x000000414661 bp 0x7ffd48797200 sp 0x7ffd487971f0
WRITE of size 1 at 0x6160000017e8 thread T0
    #0 0x414660 in luaD_pretailcall (/home/yongheng/lua_asan/lua+0x414660)
    #1 0x4429b6 in luaV_execute (/home/yongheng/lua_asan/lua+0x4429b6)
    #2 0x43d4cc in luaV_execute (/home/yongheng/lua_asan/lua+0x43d4cc)
    #3 0x415194 in luaD_callnoyield (/home/yongheng/lua_asan/lua+0x415194)
    #4 0x4127d0 in luaD_rawrunprotected (/home/yongheng/lua_asan/lua+0x4127d0)
    #5 0x415d70 in luaD_pcall (/home/yongheng/lua_asan/lua+0x415d70)
    #6 0x40bd47 in lua_pcallk (/home/yongheng/lua_asan/lua+0x40bd47)
    #7 0x4051e6 in docall (/home/yongheng/lua_asan/lua+0x4051e6)
    #8 0x40664d in pmain (/home/yongheng/lua_asan/lua+0x40664d)
    #9 0x414de1 in luaD_call (/home/yongheng/lua_asan/lua+0x414de1)
    #10 0x415194 in luaD_callnoyield (/home/yongheng/lua_asan/lua+0x415194)
    #11 0x4127d0 in luaD_rawrunprotected (/home/yongheng/lua_asan/lua+0x4127d0)
    #12 0x415d70 in luaD_pcall (/home/yongheng/lua_asan/lua+0x415d70)
    #13 0x40bd47 in lua_pcallk (/home/yongheng/lua_asan/lua+0x40bd47)
    #14 0x4049b4 in main (/home/yongheng/lua_asan/lua+0x4049b4)
    #15 0x7f6aeba2282f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #16 0x405008 in _start (/home/yongheng/lua_asan/lua+0x405008)
================================================================

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

Re: heap-buffer-overflow in luaD_pretailcall

Roberto Ierusalimschy
> We found a heap-buffer-overflow in Lua (Lua 5.4.0  Copyright (C) 1994-2020
> Lua.org, PUC-Rio)
> Try following PoC
> [...]

- What is a "heap overflow"?

- How do you generate these tests?

-- Roberto
Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

Gé Weijers
I did not report this issue, but I was able to reproduce the problem.

On Tue, Jul 7, 2020 at 9:31 AM Roberto Ierusalimschy
<[hidden email]> wrote:
>
> - What is a "heap overflow"?

The 'heap overflow' in this context means that the sanitizer library
detected that the program wrote past the end of the object.

>
> - How do you generate these tests?

Build a version of lua with the flag '-fsanitize=address', which
instruments the code to check for some kinds of stack and heap
corruption. It works by putting 'canary' values around each heap or
stack object and detecting when they're modified. It also tries to
detect use of an object after 'free' is called.
Stack and heap use (and code size) explode when you use this option.

I suggest passing the '-g' flag to gcc as well so you get line numbers
in the stack trace.  I can reproduce this issue by compiling Lua for a
32-bit machine (I just added the 32-bit libraries to a 64-bit Debian
10 install, and passed -m32 to compile and link commands. gcc version
8.0.3). The issue supposedly occurs at ldo.c line 443.

My changes to the Makefile:

diff --git a/src/Makefile b/src/Makefile
index 514593d..da8e9e9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -20,8 +20,8 @@ SYSCFLAGS=
 SYSLDFLAGS=
 SYSLIBS=

-MYCFLAGS=
-MYLDFLAGS=
+MYCFLAGS=-fsanitize=address -m32 -g
+MYLDFLAGS=-fsanitize=address -m32 -g
 MYLIBS=
 MYOBJS=


A general remark for people posting bug reports like this: please give
more information, like platform (X86 X86_64, etc.), compiler version,
OS and OS version. Run against the stock Lua release and report any
changes you made to the build process. Make it as easy as possible to
reproduce the bug.


--

Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

Roberto Ierusalimschy
> > - How do you generate these tests?

My question was how they generate the Lua code that trigger those
issues.  I am not sure whether they can be simplified; the code is quite
convoluted.

-- Roberto
Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

Petite Abeille


> On Jul 7, 2020, at 20:34, Roberto Ierusalimschy <[hidden email]> wrote:
>
> My question was how they generate the Lua code that trigger those
> issues.  I am not sure whether they can be simplified; the code is quite
> convoluted.

Interestingly, Yongheng & Rui have put sqlite through the same regime, with the same results.

Some kind of code generation fuzzer of sort.

For example:

https://www.mail-archive.com/sqlite-users@.../msg117794.html


Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

Yongheng Chen
Hi,

We generate these test cases through fuzzing. The original test case is bigger, and we use
C-reduce to reduce the test case. We can provide the original one if needed.


Yongheng

> On Jul 7, 2020, at 3:04 PM, Petite Abeille <[hidden email]> wrote:
>
>
>
>> On Jul 7, 2020, at 20:34, Roberto Ierusalimschy <[hidden email]> wrote:
>>
>> My question was how they generate the Lua code that trigger those
>> issues.  I am not sure whether they can be simplified; the code is quite
>> convoluted.
>
> Interestingly, Yongheng & Rui have put sqlite through the same regime, with the same results.
>
> Some kind of code generation fuzzer of sort.
>
> For example:
>
> https://www.mail-archive.com/sqlite-users@.../msg117794.html
>
>
Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

Petite Abeille


> On Jul 7, 2020, at 21:14, Yongheng Chen <[hidden email]> wrote:
>
> We generate these test cases through fuzzing.

Very nice. Is your fuzzer publicly available?
Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

Yongheng Chen
Very nice. Is your fuzzer publicly available?

Not yet. It might be available this fall or winter.

Yongheng

On Jul 7, 2020, at 3:34 PM, Petite Abeille <[hidden email]> wrote:

Very nice. Is your fuzzer publicly available?

Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

William Ahern
In reply to this post by Roberto Ierusalimschy
On Tue, Jul 07, 2020 at 03:34:28PM -0300, Roberto Ierusalimschy wrote:
> > > - How do you generate these tests?
>
> My question was how they generate the Lua code that trigger those
> issues.  I am not sure whether they can be simplified; the code is quite
> convoluted.

You can build with AddressSanitizer like

  make MYCFLAGS="-fsanitize=address" MYLDFLAGS="-fsanitize=address"

but I can't reproduce on Ubuntu 20.04 LTS, neither with gcc (9.3.0) nor
clang (10.0.0). It definitely would help to know more about the test
environment.

I *can* reproduce the getobjname report, though, with both GCC and clang.
Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

Gé Weijers
On Tue, Jul 7, 2020 at 9:42 PM William Ahern <[hidden email]> wrote:
> You can build with AddressSanitizer like
>
>   make MYCFLAGS="-fsanitize=address" MYLDFLAGS="-fsanitize=address"
>
> but I can't reproduce on Ubuntu 20.04 LTS, neither with gcc (9.3.0) nor
> clang (10.0.0). It definitely would help to know more about the test
> environment.

I could reproduce it on Debian 10 by compiling for 32-bit code (you
have to install 32-bit glibc and some other libraries if you're
running a 64-bit kernel)
Pass -m32 to the compiler.

--

Reply | Threaded
Open this post in threaded view
|

Re: heap-buffer-overflow in luaD_pretailcall

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

 Rui> 0x6160000017e8 at pc 0x000000414661 bp 0x7ffd48797200 sp 0x7ffd487971f0
 Rui> WRITE of size 1 at 0x6160000017e8 thread T0
 Rui>     #0 0x414660 in luaD_pretailcall (/home/yongheng/lua_asan/lua+0x414660)

So this seems to be a rather fundamental issue in checkstackGC; it
ensures that there's stack space beyond L->top for the specified number
of entries, reallocating the stack if need be, but then it possibly
performs a garbage collection, and the garbage collector can and will
_immediately shrink the stack down again_. This can (and in this case
does) undo the stack growth that was just done, and so the
argument-completion loop in pretailcall stomps off the end of the stack.

Maybe something should have been assigning to ci->top before allowing
the GC to run, to protect the newly-allocated stack entries?

--
Andrew.