berry-lang / berry

A ultra-lightweight embedded scripting language optimized for microcontrollers.
https://berry-lang.github.io
MIT License
782 stars 95 forks source link

fix: prevent buffer overflow when lexing very long real numbers #420

Closed alufers closed 2 months ago

alufers commented 2 months ago

Use save_char instead of manually adding the null terminator - the buffer might not have grown enough to fit it, causing an out-of-bounds write.

Added test case to catch this.

It used to crash when running with ASAN like this:

=================================================================
==171884==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50c0000000c0 at pc 0x5d58b5be50ef bp 0x7fff24339b10 sp 0x7fff24339b00
WRITE of size 1 at 0x50c0000000c0 thread T0
    #0 0x5d58b5be50ee in scan_decimal src/be_lexer.c:357
    #1 0x5d58b5be55f5 in scan_numeral src/be_lexer.c:375
    #2 0x5d58b5bea774 in lexer_next src/be_lexer.c:781
    #3 0x5d58b5bebe64 in be_lexer_scan_next src/be_lexer.c:838
    #4 0x5d58b5c206f5 in call_expr src/be_parser.c:811
    #5 0x5d58b5c220f7 in suffix_expr src/be_parser.c:927
    #6 0x5d58b5c25d5d in sub_expr src/be_parser.c:1083
    #7 0x5d58b5c26774 in walrus_expr src/be_parser.c:1112
    #8 0x5d58b5c27004 in expr src/be_parser.c:1138
    #9 0x5d58b5c24385 in assign_expr src/be_parser.c:1010
    #10 0x5d58b5c27043 in expr_stmt src/be_parser.c:1143
    #11 0x5d58b5c32ad5 in statement src/be_parser.c:1779
    #12 0x5d58b5c332cb in stmtlist src/be_parser.c:1791
    #13 0x5d58b5c33b8f in mainfunc src/be_parser.c:1812
    #14 0x5d58b5c34177 in be_parser_source src/be_parser.c:1830
    #15 0x5d58b5bbafa8 in m_parser src/be_exec.c:166
    #16 0x5d58b5bb9572 in be_execprotected src/be_exec.c:122
    #17 0x5d58b5bbb413 in be_protectedparser src/be_exec.c:183
    #18 0x5d58b5bbbce8 in fileparser src/be_exec.c:228
    #19 0x5d58b5bbc46e in be_loadmode src/be_exec.c:272
    #20 0x5d58b5c8e94d in doscript default/berry.c:215
    #21 0x5d58b5c8eb21 in load_script default/berry.c:233
    #22 0x5d58b5c90309 in analysis_args default/berry.c:396
    #23 0x5d58b5c903e5 in main default/berry.c:404
    #24 0x765e67c43ccf  (/usr/lib/libc.so.6+0x25ccf) (BuildId: c0caa0b7709d3369ee575fcd7d7d0b0fc48733af)
    #25 0x765e67c43d89 in __libc_start_main (/usr/lib/libc.so.6+0x25d89) (BuildId: c0caa0b7709d3369ee575fcd7d7d0b0fc48733af)
    #26 0x5d58b5b60724 in _start (/tmp/berry/berry+0x18b724) (BuildId: 467e6084a589ea218e145696ffd370bf2f254090)

0x50c0000000c0 is located 0 bytes after 128-byte region [0x50c000000040,0x50c0000000c0)
allocated by thread T0 here:
    #0 0x765e67ee007a in __interceptor_realloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:85
    #1 0x5d58b5c02bf6 in be_realloc src/be_mem.c:141
    #2 0x5d58b5be20f1 in save_char src/be_lexer.c:124
    #3 0x5d58b5be2518 in save src/be_lexer.c:134
    #4 0x5d58b5be4391 in scan_realexp src/be_lexer.c:295
    #5 0x5d58b5be4ed7 in scan_decimal src/be_lexer.c:353
    #6 0x5d58b5be55f5 in scan_numeral src/be_lexer.c:375
    #7 0x5d58b5bea774 in lexer_next src/be_lexer.c:781
    #8 0x5d58b5bebe64 in be_lexer_scan_next src/be_lexer.c:838
    #9 0x5d58b5c206f5 in call_expr src/be_parser.c:811
    #10 0x5d58b5c220f7 in suffix_expr src/be_parser.c:927
    #11 0x5d58b5c25d5d in sub_expr src/be_parser.c:1083
    #12 0x5d58b5c26774 in walrus_expr src/be_parser.c:1112
    #13 0x5d58b5c27004 in expr src/be_parser.c:1138
    #14 0x5d58b5c24385 in assign_expr src/be_parser.c:1010
    #15 0x5d58b5c27043 in expr_stmt src/be_parser.c:1143
    #16 0x5d58b5c32ad5 in statement src/be_parser.c:1779
    #17 0x5d58b5c332cb in stmtlist src/be_parser.c:1791
    #18 0x5d58b5c33b8f in mainfunc src/be_parser.c:1812
    #19 0x5d58b5c34177 in be_parser_source src/be_parser.c:1830
    #20 0x5d58b5bbafa8 in m_parser src/be_exec.c:166
    #21 0x5d58b5bb9572 in be_execprotected src/be_exec.c:122
    #22 0x5d58b5bbb413 in be_protectedparser src/be_exec.c:183
    #23 0x5d58b5bbbce8 in fileparser src/be_exec.c:228
    #24 0x5d58b5bbc46e in be_loadmode src/be_exec.c:272
    #25 0x5d58b5c8e94d in doscript default/berry.c:215
    #26 0x5d58b5c8eb21 in load_script default/berry.c:233
    #27 0x5d58b5c90309 in analysis_args default/berry.c:396
    #28 0x5d58b5c903e5 in main default/berry.c:404
    #29 0x765e67c43ccf  (/usr/lib/libc.so.6+0x25ccf) (BuildId: c0caa0b7709d3369ee575fcd7d7d0b0fc48733af)

SUMMARY: AddressSanitizer: heap-buffer-overflow src/be_lexer.c:357 in scan_decimal
Shadow bytes around the buggy address:
  0x50bffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x50bffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x50bfffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x50bfffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x50c000000000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x50c000000080: 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa
  0x50c000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x50c000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x50c000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x50c000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x50c000000300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
==171884==ABORTING