-
Notifications
You must be signed in to change notification settings - Fork 606
Open
Description
Description
We discovered a Heap-buffer-overflow vulnerability in Wren. The crash occurs in the compiler's lexer (peekChar) when parsing a source file containing a malformed sequence of quotes (likely triggering raw string parsing).
The ASAN report indicates a READ violation of size 1, occurring immediately after the allocated source buffer.
Environment
- OS: Linux x86_64
- Complier: Clang
- Build Configuration: Release mode with ASan enabled.
Vulnerability Details
- Target: Wren (wren-lang)
- Vulnerability Type: CWE-125: Out-of-bounds Read
- Function: peekChar (called by readRawString)
- Location: src/vm/wren_compiler.c:641
- Root Cause Analysis: The crash happens when the lexer attempts to parse a raw string literal (triple quotes """).
- The PoC ends with a sequence of many quotes: nt(""""""""".
- nextToken calls readRawString to handle the string literal.
- Inside readRawString, the parser consumes characters looking for the closing delimiter.
- It appears the loop logic inside readRawString (or its usage of peekChar) fails to detect the end of the source buffer (EOF/Null terminator) correctly when faced with incomplete or excessive quotes, causing it to read one byte past the end of the heap-allocated source string.
Reproduce
- Build wren and harness with Release optimization and ASAN enabled.
harness.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wren.h"
void writeFn(WrenVM* vm, const char* text) {
}
void errorFn(WrenVM* vm, WrenErrorType type, const char* module, int line, const char* message) {
}
int main(int argc, char** argv) {
if (argc < 2) return 1;
FILE* f = fopen(argv[1], "rb");
if (!f) return 1;
fseek(f, 0, SEEK_END);
long length = ftell(f);
fseek(f, 0, SEEK_SET);
char* buffer = (char*)malloc(length + 1);
if (!buffer) {
fclose(f);
return 1;
}
if (fread(buffer, 1, length, f) != (size_t)length) {
free(buffer);
fclose(f);
return 1;
}
buffer[length] = '\0';
fclose(f);
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = writeFn;
config.errorFn = errorFn;
WrenVM* vm = wrenNewVM(&config);
WrenInterpretResult result = wrenInterpret(vm, "main", buffer);
wrenFreeVM(vm);
free(buffer);
return 0;
}
- Run with the crashing file:
./bin/harness repro
ASAN report
==71585==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x504000000038 at pc 0x55ef7240e1b4 bp 0x7ffd70a28ab0 sp 0x7ffd70a28aa8
READ of size 1 at 0x504000000038 thread T0
#0 0x55ef7240e1b3 in peekChar /src/wren/projects/make/../../src/vm/wren_compiler.c:641:10
#1 0x55ef7240e1b3 in readRawString /src/wren/projects/make/../../src/vm/wren_compiler.c:911:15
#2 0x55ef7240e1b3 in nextToken /src/wren/projects/make/../../src/vm/wren_compiler.c:1186:11
#3 0x55ef72408325 in consume /src/wren/projects/make/../../src/vm/wren_compiler.c:1269:3
#4 0x55ef72408325 in wrenCompile /src/wren/projects/make/../../src/vm/wren_compiler.c:3820:9
#5 0x55ef723f4aa3 in compileInModule /src/wren/projects/make/../../src/vm/wren_vm.c:484:15
#6 0x55ef723f3f26 in wrenCompileSource /src/wren/projects/make/../../src/vm/wren_vm.c:1538:25
#7 0x55ef723f3f26 in wrenInterpret /src/wren/projects/make/../../src/vm/wren_vm.c:1517:25
#8 0x55ef723e8ca5 in main /src/wren/fuzz_wren.c:51:34
#9 0x7fc0075061c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#10 0x7fc00750628a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#11 0x55ef723075c4 in _start (/src/wren/bin/fuzz_wren+0x365c4) (BuildId: 5d78be029a4b6a34067ee0d0f65b83b8780504cc)
0x504000000038 is located 0 bytes after 40-byte region [0x504000000010,0x504000000038)
allocated by thread T0 here:
#0 0x55ef723a73f3 in malloc (/src/wren/bin/fuzz_wren+0xd63f3) (BuildId: 5d78be029a4b6a34067ee0d0f65b83b8780504cc)
#1 0x55ef723e8bb5 in main /src/wren/fuzz_wren.c:26:27
#2 0x7fc0075061c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#3 0x7fc00750628a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#4 0x55ef723075c4 in _start (/src/wren/bin/fuzz_wren+0x365c4) (BuildId: 5d78be029a4b6a34067ee0d0f65b83b8780504cc)
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/wren/projects/make/../../src/vm/wren_compiler.c:641:10 in peekChar
Shadow bytes around the buggy address:
0x503ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x503ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x503ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x503fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x503fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x504000000000: fa fa 00 00 00 00 00[fa]fa fa 00 00 00 00 00 fa
0x504000000080: fa fa 00 00 00 00 07 fa fa fa 00 00 00 00 07 fa
0x504000000100: fa fa 00 00 00 00 02 fa fa fa 00 00 00 00 06 fa
0x504000000180: fa fa 00 00 00 00 06 fa fa fa 00 00 00 00 06 fa
0x504000000200: fa fa 00 00 00 00 00 01 fa fa 00 00 00 00 05 fa
0x504000000280: fa fa 00 00 00 00 06 fa fa fa 00 00 00 00 06 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
==71585==ABORTING
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels