Skip to content

[Bug] Stack-buffer-overflow in printError via unsafe vsprintf #1221

Description

@oneafter

Description

We discovered a Stack-buffer-overflow vulnerability in the Wren compiler. The crash occurs in the printError function (called by error) when handling error messages during class/method compilation.

The code uses the unsafe vsprintf function to format an error message into a fixed-size stack buffer without checking if the resulting string fits, leading to a write overflow.

Environment

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

Vulnerability Details

  • Target: Wren (wren-lang)
  • Vulnerability Type: CWE-121: Stack-based Buffer Overflow
  • Function: printError / vsprintf
  • Location: src/vm/wren_compiler.c:432
  • Root Cause Analysis: The function error (or printError inlined/called) likely defines a local char buffer (e.g., message). The ASAN report shows this buffer is approximately 159 bytes long ([32, 191)). The code calls vsprintf(message, format, args) without limiting the output size. When declareMethod triggers an error with a long format string or arguments (e.g., a very long method name), vsprintf writes past the bounds of message, corrupting the stack.

Reproduce

  1. 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;
}
  1. Run with the crashing file:
./bin/harness repro
ASAN report
==49765==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7f4dbe1058bf at pc 0x56515ec0d6b4 bp 0x7ffcaacf2470 sp 0x7ffcaacf1c10
WRITE of size 158 at 0x7f4dbe1058bf thread T0
    #0 0x56515ec0d6b3 in vsprintf (/src/wren/bin/fuzz_wren+0x5d6b3) (BuildId: 5d78be029a4b6a34067ee0d0f65b83b8780504cc)
    #1 0x56515ecdb5c4 in printError /src/wren/projects/make/../../src/vm/wren_compiler.c:432:13
    #2 0x56515ecdb5c4 in error /src/wren/projects/make/../../src/vm/wren_compiler.c:490:5
    #3 0x56515ed0046d in declareMethod /src/wren/projects/make/../../src/vm/wren_compiler.c:3340:7
    #4 0x56515ed0046d in method /src/wren/projects/make/../../src/vm/wren_compiler.c:3482:22
    #5 0x56515ed0046d in classDefinition /src/wren/projects/make/../../src/vm/wren_compiler.c:3598:10
    #6 0x56515ecedcdc in definition /src/wren/projects/make/../../src/vm/wren_compiler.c
    #7 0x56515ece703d in wrenCompile /src/wren/projects/make/../../src/vm/wren_compiler.c:3815:7
    #8 0x56515ecd3aa3 in compileInModule /src/wren/projects/make/../../src/vm/wren_vm.c:484:15
    #9 0x56515ecd2f26 in wrenCompileSource /src/wren/projects/make/../../src/vm/wren_vm.c:1538:25
    #10 0x56515ecd2f26 in wrenInterpret /src/wren/projects/make/../../src/vm/wren_vm.c:1517:25
    #11 0x56515ecc7ca5 in main /src/wren/fuzz_wren.c:51:34
    #12 0x7f4dbfd271c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
    #13 0x7f4dbfd2728a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
    #14 0x56515ebe65c4 in _start (/src/wren/bin/fuzz_wren+0x365c4) (BuildId: 5d78be029a4b6a34067ee0d0f65b83b8780504cc)

Address 0x7f4dbe1058bf is located in stack of thread T0 at offset 191 in frame
    #0 0x56515ecdadaf in error /src/wren/projects/make/../../src/vm/wren_compiler.c:460

  This frame has 5 object(s):
    [32, 191) 'message.i63' (line 430)
    [256, 415) 'message.i44' (line 430) <== Memory access at offset 191 partially underflows this variable
    [480, 639) 'message.i' (line 430)
    [704, 728) 'args' (line 467)
    [768, 847) 'label' (line 481)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/src/wren/bin/fuzz_wren+0x5d6b3) (BuildId: 5d78be029a4b6a34067ee0d0f65b83b8780504cc) in vsprintf
Shadow bytes around the buggy address:
  0x7f4dbe105600: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f4dbe105680: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f4dbe105700: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f4dbe105780: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f4dbe105800: f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7f4dbe105880: 00 00 00 00 00 00 00[07]f2 f2 f2 f2 f2 f2 f2 f2
  0x7f4dbe105900: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
  0x7f4dbe105980: f8 f8 f8 f8 f2 f2 f2 f2 f2 f2 f2 f2 f8 f8 f8 f8
  0x7f4dbe105a00: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
  0x7f4dbe105a80: f2 f2 f2 f2 f2 f2 f2 f2 00 00 00 f2 f2 f2 f2 f2
  0x7f4dbe105b00: 00 00 00 00 00 00 00 00 00 07 f3 f3 f3 f3 f3 f3
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
==49765==ABORTING

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions