Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multiple stack buffer overflows inside jslex parsing #1425

Closed
hongxuchen opened this issue May 19, 2018 · 9 comments
Closed

multiple stack buffer overflows inside jslex parsing #1425

hongxuchen opened this issue May 19, 2018 · 9 comments

Comments

@hongxuchen
Copy link

We found with our fuzzer several buffer overflow errors that can be triggered with address sanitizer. Please see the following for details.

@hongxuchen
Copy link
Author

hongxuchen commented May 19, 2018

With the project LICENSE and ChangeLog file as the input for espruino, the error is like:


 ____                 _ 
|  __|___ ___ ___ _ _|_|___ ___ 
|  __|_ -| . |  _| | | |   | . |
|____|___|  _|_| |___|_|_|_|___|
         |_| espruino.com
 1v97.104 (c) 2018 G.Williams

Espruino is Open Source. Our work is supported
only by sales of official boards and donations:
http://espruino.com/Donate

=================================================================
==27535==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffdf698b054 at pc 0x7ff69c02146b bp 0x7ffdf698b010 sp 0x7ffdf698a7b8
WRITE of size 18 at 0x7ffdf698b054 thread T0
    #0 0x7ff69c02146a in strncat (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a)
    #1 0x55dba3ad51fb in jslMatch src/jslex.c:864
    #2 0x55dba3b1bf16 in jspeFunctionArguments src/jsparse.c:341
    #3 0x55dba3b1cf33 in jspeFunctionDefinition src/jsparse.c:463
    #4 0x55dba3b298bf in jspeStatementFunctionDecl src/jsparse.c:2614
    #5 0x55dba3b2a8ac in jspeStatement src/jsparse.c:2701
    #6 0x55dba3b2606c in jspeBlockOrStatement src/jsparse.c:2079
    #7 0x55dba3b2617c in jspParse src/jsparse.c:2091
    #8 0x55dba3b2b77b in jspEvaluateVar src/jsparse.c:2899
    #9 0x55dba3b2babb in jspEvaluate src/jsparse.c:2931
    #10 0x55dba3d072d3 in main targets/linux/main.c:330
    #11 0x7ff69b5fbb96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #12 0x55dba3ac1779 in _start (/home/hongxu/tests/Espruino/espruino+0x46779)

Address 0x7ffdf698b054 is located in stack of thread T0 at offset 52 in frame
    #0 0x55dba3ad4f6f in jslMatch src/jslex.c:860

  This frame has 2 object(s):
    [32, 52) 'gotStr:862' <== Memory access at offset 52 overflows this variable
    [96, 116) 'expStr:863'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a) in strncat
Shadow bytes around the buggy address:
  0x10003ed295b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10003ed295c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10003ed295d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10003ed295e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10003ed295f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10003ed29600: 00 00 00 00 f1 f1 f1 f1 00 00[04]f2 f2 f2 f2 f2
  0x10003ed29610: 00 00 04 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x10003ed29620: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10003ed29630: f1 f1 f1 f1 00 00 00 00 00 00 00 00 01 f2 f2 f2
  0x10003ed29640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10003ed29650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==27535==ABORTING

@hongxuchen
Copy link
Author

A similar however different error is like:

=================================================================
==25796==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcb407e724 at pc 0x7fe6f8ad046b bp 0x7ffcb407e6a0 sp 0x7ffcb407de48
WRITE of size 18 at 0x7ffcb407e724 thread T0
    #0 0x7fe6f8ad046a in strncat (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a)
    #1 0x564365d7c4d4 in jslGetTokenString src/jslex.c:825
    #2 0x564365d7ca91 in jslMatch src/jslex.c:864
    #3 0x564365da54cb in jspeParseFunctionCallBrackets src/jsparse.c:491
    #4 0x564365da713d in jspeFunctionCall src/jsparse.c:905
    #5 0x564365da870a in jspeFactorFunctionCall src/jsparse.c:1224
    #6 0x564365dac76f in jspePostfixExpression src/jsparse.c:1765
    #7 0x564365dacac6 in jspeUnaryExpression src/jsparse.c:1791
    #8 0x564365dad16a in jspeBinaryExpression src/jsparse.c:1919
    #9 0x564365dad3c5 in jspeConditionalExpression src/jsparse.c:1955
    #10 0x564365dadb01 in jspeAssignmentExpression src/jsparse.c:2020
    #11 0x564365dadb22 in jspeExpression src/jsparse.c:2026
    #12 0x564365db1f40 in jspeStatement src/jsparse.c:2673
    #13 0x564365dae0a1 in jspeBlockOrStatement src/jsparse.c:2079
    #14 0x564365dae1ab in jspParse src/jsparse.c:2091
    #15 0x564365db340c in jspEvaluateVar src/jsparse.c:2899
    #16 0x564365db3767 in jspEvaluate src/jsparse.c:2931
    #17 0x564365e5ac8d in main targets/linux/main.c:330
    #18 0x7fe6f80aab96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #19 0x564365d76119 in _start (/home/hongxu/tests/Espruino-asan/espruino+0x36119)

Address 0x7ffcb407e724 is located in stack of thread T0 at offset 52 in frame
    #0 0x564365d7c996 in jslMatch src/jslex.c:860

  This frame has 2 object(s):
    [32, 52) 'gotStr' <== Memory access at offset 52 overflows this variable
    [96, 116) 'expStr'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a) in strncat
Shadow bytes around the buggy address:
  0x100016807c90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100016807ca0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100016807cb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100016807cc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100016807cd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
=>0x100016807ce0: f1 f1 00 00[04]f2 f2 f2 f2 f2 00 00 04 f2 00 00
  0x100016807cf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100016807d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100016807d10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100016807d20: 00 00 f1 f1 f1 f1 00 f2 f2 f2 f2 f2 f2 f2 00 f2
  0x100016807d30: f2 f2 f2 f2 f2 f2 00 00 00 00 00 00 00 00 f2 f2
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
==25796==ABORTING

There are multiple files that can trigger this:
test_0.txt
test_1.txt

@hongxuchen
Copy link
Author

jslGetTokenString at jslex.c:828:

=================================================================
==17194==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffef62298a4 at pc 0x7f712ffbd46b bp 0x7ffef6229820 sp 0x7ffef6228fc8
WRITE of size 21 at 0x7ffef62298a4 thread T0
    #0 0x7f712ffbd46a in strncat (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a)
    #1 0x55dc6f435559 in jslGetTokenString src/jslex.c:828
    #2 0x55dc6f435a91 in jslMatch src/jslex.c:864
    #3 0x55dc6f460dd7 in jspeFactorMember src/jsparse.c:1107
    #4 0x55dc6f46155a in jspeFactorFunctionCall src/jsparse.c:1200
    #5 0x55dc6f46576f in jspePostfixExpression src/jsparse.c:1765
    #6 0x55dc6f465ac6 in jspeUnaryExpression src/jsparse.c:1791
    #7 0x55dc6f46616a in jspeBinaryExpression src/jsparse.c:1919
    #8 0x55dc6f4663c5 in jspeConditionalExpression src/jsparse.c:1955
    #9 0x55dc6f466b01 in jspeAssignmentExpression src/jsparse.c:2020
    #10 0x55dc6f466b22 in jspeExpression src/jsparse.c:2026
    #11 0x55dc6f46af40 in jspeStatement src/jsparse.c:2673
    #12 0x55dc6f4670a1 in jspeBlockOrStatement src/jsparse.c:2079
    #13 0x55dc6f4671ab in jspParse src/jsparse.c:2091
    #14 0x55dc6f46c40c in jspEvaluateVar src/jsparse.c:2899
    #15 0x55dc6f46c767 in jspEvaluate src/jsparse.c:2931
    #16 0x55dc6f513c8d in main targets/linux/main.c:330
    #17 0x7f712f597b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #18 0x55dc6f42f119 in _start (/home/hongxu/tests/Espruino-asan/espruino+0x36119)

Address 0x7ffef62298a4 is located in stack of thread T0 at offset 52 in frame
    #0 0x55dc6f435996 in jslMatch src/jslex.c:860

  This frame has 2 object(s):
    [32, 52) 'gotStr' <== Memory access at offset 52 overflows this variable
    [96, 116) 'expStr'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a) in strncat
Shadow bytes around the buggy address:
  0x10005ec3d2c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005ec3d2d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005ec3d2e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005ec3d2f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005ec3d300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
=>0x10005ec3d310: f1 f1 00 00[04]f2 f2 f2 f2 f2 00 00 04 f2 00 00
  0x10005ec3d320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005ec3d330: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 f2 f2 f2
  0x10005ec3d340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005ec3d350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005ec3d360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==17194==ABORTING

sample input files:
test_2.txt
test_3.txt

@hongxuchen
Copy link
Author

jslGetTokenString at jslex.c:829:

=================================================================
==20838==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc2d082c34 at pc 0x7f1b52d0246b bp 0x7ffc2d082bb0 sp 0x7ffc2d082358
WRITE of size 2 at 0x7ffc2d082c34 thread T0
    #0 0x7f1b52d0246a in strncat (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a)
    #1 0x5620e4dc4570 in jslGetTokenString src/jslex.c:829
    #2 0x5620e4dc4a91 in jslMatch src/jslex.c:864
    #3 0x5620e4ded4cb in jspeParseFunctionCallBrackets src/jsparse.c:491
    #4 0x5620e4def13d in jspeFunctionCall src/jsparse.c:905
    #5 0x5620e4df070a in jspeFactorFunctionCall src/jsparse.c:1224
    #6 0x5620e4df476f in jspePostfixExpression src/jsparse.c:1765
    #7 0x5620e4df4ac6 in jspeUnaryExpression src/jsparse.c:1791
    #8 0x5620e4df516a in jspeBinaryExpression src/jsparse.c:1919
    #9 0x5620e4df53c5 in jspeConditionalExpression src/jsparse.c:1955
    #10 0x5620e4df5b01 in jspeAssignmentExpression src/jsparse.c:2020
    #11 0x5620e4df5b22 in jspeExpression src/jsparse.c:2026
    #12 0x5620e4df9f40 in jspeStatement src/jsparse.c:2673
    #13 0x5620e4df60a1 in jspeBlockOrStatement src/jsparse.c:2079
    #14 0x5620e4df61ab in jspParse src/jsparse.c:2091
    #15 0x5620e4dfb40c in jspEvaluateVar src/jsparse.c:2899
    #16 0x5620e4dfb767 in jspEvaluate src/jsparse.c:2931
    #17 0x5620e4ea2c8d in main targets/linux/main.c:330
    #18 0x7f1b522dcb96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #19 0x5620e4dbe119 in _start (/home/hongxu/tests/Espruino-asan/espruino+0x36119)

Address 0x7ffc2d082c34 is located in stack of thread T0 at offset 52 in frame
    #0 0x5620e4dc4996 in jslMatch src/jslex.c:860

  This frame has 2 object(s):
    [32, 52) 'gotStr' <== Memory access at offset 52 overflows this variable
    [96, 116) 'expStr'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a) in strncat
Shadow bytes around the buggy address:
  0x100005a08530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100005a08540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100005a08550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100005a08560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100005a08570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100005a08580: f1 f1 f1 f1 00 00[04]f2 f2 f2 f2 f2 00 00 04 f2
  0x100005a08590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100005a085a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100005a085b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100005a085c0: 00 00 00 00 f1 f1 f1 f1 00 f2 f2 f2 f2 f2 f2 f2
  0x100005a085d0: 00 f2 f2 f2 f2 f2 f2 f2 00 00 00 00 00 00 00 00
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
==20838==ABORTING

sampe input files:

test_4.txt
test_5.txt

@gfwilliams
Copy link
Member

I'm not sure I understand the issue here. Can you explain in more detail?

The LICENSE and ChangeLog files (and test_0.txt that I just testes) just fail with SyntaxErrors.

The first stack trace you give shows:

==27535==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffdf698b054 at pc 0x7ff69c02146b bp 0x7ffdf698b010 sp 0x7ffdf698a7b8
WRITE of size 18 at 0x7ffdf698b054 thread T0
    #0 0x7ff69c02146a in strncat (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9946a)
    #1 0x55dba3ad51fb in jslMatch src/jslex.c:864

But strncat is writing 18 bytes to an array gotStr that is 20 bytes long. Sure, it's on the stack, but that's not any kind of overflow or anything to be worried about?

@hongxuchen
Copy link
Author

Sorry I had't had time to read the exact implementation but just reported as the address sanitizer reported. In my opinion the overflow does not overrun all the stack but only some in the stack.

@gfwilliams
Copy link
Member

I'm not sure I understand... But you believe it does overflow some of it?

@hongxuchen
Copy link
Author

We checked strncat's manual just now, it says:

If src contains n or more bytes, strncat() writes n+1 bytes to dest (n from src plus the terminating null byte). Therefore, the size of dest must be at least strlen(dest)+n+1.

When entering jslGetTokenValueAsString, the return string can sometimes be >=20, therefore n+1=21 is possible, in addition, strlen(dest)>=0, which can overrun the string during strncat.

In Changelog, this happens abount 20 iterations when the return string is jsvObjectGetChild whose length is 17, while str is already "ID:", causing one offset overrun. However in other case, we can make it overrun more bytes.

@gfwilliams
Copy link
Member

Wow, thanks. You learn something every day - I'll have to be careful of that with strncat - it makes the n bit almost useless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants