Skip to content

Buffer underflow in ary_fill_exec #6650

@tim-becker

Description

@tim-becker

Description: Pointer underflow when start is negative: __fill_exec does not validate start<0, so ptr = ARY_PTR(ary)+start underflows, and ptr[i] writes before the array bounds (lines 945–947).

Trigger conditions: Call Array#__fill_exec with a negative start and positive length in Ruby code passed to mrb_load_string.

Harness name: mruby_fuzzer

Crashing input:

a = Array.new(20,0)
a.__fill_exec(-30,10,nil)

Crash output:

+ FUZZER=mruby_fuzzer
+ shift
+ '[' '!' -v TESTCASE ']'
+ TESTCASE=/testcase
+ '[' '!' -f /testcase ']'
+ export RUN_FUZZER_MODE=interactive
+ RUN_FUZZER_MODE=interactive
+ export FUZZING_ENGINE=libfuzzer
+ FUZZING_ENGINE=libfuzzer
+ export SKIP_SEED_CORPUS=1
+ SKIP_SEED_CORPUS=1
+ run_fuzzer mruby_fuzzer /testcase
sysctl: setting key "vm.mmap_rnd_bits", ignoring: Read-only file system
Dictionary: 102 entries
/out/mruby_fuzzer: Running 1 inputs 1 time(s) each.
Running: /testcase
AddressSanitizer:DEADLYSIGNAL
=================================================================
==43==ERROR: AddressSanitizer: SEGV on unknown address 0x510fffffff50 (pc 0x7f377e9bac1a bp 0x7fff8f12ceb0 sp 0x7fff8f12c668 T0)
==43==The signal is caused by a WRITE memory access.
SCARINESS: 30 (wild-addr-write)
Stack Frame #0  /build/glibc-B3wQXB/glibc-2.31/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:314
Stack Frame #1 in __asan_memcpy /src/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:63:3
Stack Frame #2 in ary_fill_exec array.c
Stack Frame #3 in mrb_vm_exec (/out/mruby_fuzzer+0x2e9297)
Stack Frame #4 in mrb_vm_run (/out/mruby_fuzzer+0x2d18e2)
Stack Frame #5 in mrb_top_run (/out/mruby_fuzzer+0x32d589)
Stack Frame #6 in mrb_load_exec (/out/mruby_fuzzer+0x3c61c5)
Stack Frame #7 in mrb_load_nstring_cxt (/out/mruby_fuzzer+0x3c712c)
Stack Frame #8 in mrb_load_string_cxt (/out/mruby_fuzzer+0x3c7260)
Stack Frame #9 in mrb_load_string (/out/mruby_fuzzer+0x3c72d8)
Stack Frame #10 in LLVMFuzzerTestOneInput (/out/mruby_fuzzer+0x2a7c5b)
Stack Frame #11 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
Stack Frame #12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:327:6
Stack Frame #13 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:862:9
Stack Frame #14 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
Stack Frame #15 in __libc_start_main /build/glibc-B3wQXB/glibc-2.31/csu/../csu/libc-start.c:308:16
Stack Frame #16 in _start (/out/mruby_fuzzer+0x13fb0d)

DEDUP_TOKEN: __asan_memcpy--ary_fill_exec--mrb_vm_exec--mrb_vm_run
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /build/glibc-B3wQXB/glibc-2.31/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:314 
==43==ABORTING

/out/mruby_fuzzer -rss_limit_mb=2560 -timeout=25 /testcase -dict=mruby.dict -only_ascii=1 < /dev/null

Patch:

--- a/mrbgems/mruby-array-ext/src/array.c
+++ b/mrbgems/mruby-array-ext/src/array.c
@@ -929,6 +929,13 @@
   struct RArray *ary = mrb_ary_ptr(self);
   mrb_int ary_len = ARY_LEN(ary);
 
+  /* Normalize negative start index */
+  if (start < 0) start += ary_len;
+  if (start < 0) start = 0;
+  
+  /* Ensure length is non-negative */
+  if (length < 0) length = 0;
+
   /* Extend array if necessary */
   if (start + length > ary_len) {
     mrb_ary_resize(mrb, self, start + length);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions