Skip to content

Out-of-bounds write in srled8: decompressor ignores outlen limit for run writes #12

@hgarrereyn

Description

@hgarrereyn

srled8 can write beyond the specified out_len for certain crafted inputs. See the following test case and crash report:

testcase

#include <cstdint>
#include <vector>
extern "C" {
#include "trle.h"
}
int main(){
  // Construct a minimal compressed stream that demands a long run write.
  // Format: [escape=e=0][varlen r=100][byte c='A']
  // This triggers the r>=3 branch: r = r-3+4 => 101 bytes written.
  const uint8_t e = 0;
  const unsigned char in[] = { 0, 100, 'A' };
  std::vector<unsigned char> out(16); // Intentionally small to show that outlen is ignored
  // Expected behavior: detect insufficient space and return an error without writing past outlen.
  // Actual behavior: writes 101 bytes into a 16-byte buffer (heap-buffer-overflow).
  (void)srled8(in, sizeof(in), out.data(), (unsigned)out.size(), e);
  return 0;
}

crash report

{
  "Date": "2025-09-21T17:42:21.031865+00:00",
  "Uname": "Linux d16d63cae79c 5.15.0-140-generic #150-Ubuntu SMP Sat Apr 12 06:00:09 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux",
  "OS": "Ubuntu",
  "OSRelease": "22.04",
  "Architecture": "amd64",
  "ExecutablePath": "/tmp/tmpq209ulzd/reproducer",
  "ProcEnviron": [
    "PREFIX=/fuzz/install",
    "LIBAFL_EDGES_MAP_SIZE=800000",
    "PWD=/fuzz/workspace",
    "CXX=gf_libafl_cxx",
    "GRAPHFUZZ_USE_ASAN=1",
    "HOME=/root",
    "ASAN_OPTIONS=hard_rss_limit_mb=1024:detect_leaks=0",
    "TERM=xterm-256color",
    "SHLVL=1",
    "LD_LIBRARY_PATH=/fuzz/install/lib",
    "PATH=/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    "CC=gf_libafl_cc",
    "DEBIAN_FRONTEND=noninteractive",
    "OLDPWD=/fuzz/src",
    "_=/usr/local/bin/agfi"
  ],
  "ProcCmdline": "/tmp/tmpq209ulzd/reproducer",
  "Stdin": "",
  "ProcStatus": [],
  "ProcMaps": [],
  "ProcFiles": [],
  "NetworkConnections": [],
  "CrashSeverity": {
    "Type": "EXPLOITABLE",
    "ShortDescription": "heap-buffer-overflow(write)",
    "Description": "Heap buffer overflow",
    "Explanation": "The target writes data past the end, or before the beginning, of the intended heap buffer."
  },
  "Stacktrace": [
    "    #0 0x55555561a98f in __asan_memset (/tmp/tmpq209ulzd/reproducer+0xc698f) (BuildId: d100254902ddb65c25c4d8ea24192dea2494b7ac)",
    "    #1 0x55555565becd in _srled8 /fuzz/src/trled.c:112:9",
    "    #2 0x55555565b4d5 in main /tmp/tmpq209ulzd/reproducer.cpp:15:9",
    "    #3 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
    "    #4 0x7ffff7a6de3f in __libc_start_main csu/../csu/libc-start.c:392:3",
    "    #5 0x5555555802f4 in _start (/tmp/tmpq209ulzd/reproducer+0x2c2f4) (BuildId: d100254902ddb65c25c4d8ea24192dea2494b7ac)"
  ],
  "Registers": {},
  "Disassembly": [],
  "Package": "",
  "PackageVersion": "",
  "PackageArchitecture": "",
  "PackageDescription": "",
  "AsanReport": [
    "==156==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000020 at pc 0x55555561a990 bp 0x7fffffffe9c0 sp 0x7fffffffe190",
    "WRITE of size 101 at 0x502000000020 thread T0",
    "    #0 0x55555561a98f in __asan_memset (/tmp/tmpq209ulzd/reproducer+0xc698f) (BuildId: d100254902ddb65c25c4d8ea24192dea2494b7ac)",
    "    #1 0x55555565becd in _srled8 /fuzz/src/trled.c:112:9",
    "    #2 0x55555565b4d5 in main /tmp/tmpq209ulzd/reproducer.cpp:15:9",
    "    #3 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
    "    #4 0x7ffff7a6de3f in __libc_start_main csu/../csu/libc-start.c:392:3",
    "    #5 0x5555555802f4 in _start (/tmp/tmpq209ulzd/reproducer+0x2c2f4) (BuildId: d100254902ddb65c25c4d8ea24192dea2494b7ac)",
    "",
    "0x502000000020 is located 0 bytes after 16-byte region [0x502000000010,0x502000000020)",
    "allocated by thread T0 here:",
    "    #0 0x55555565910d in operator new(unsigned long) (/tmp/tmpq209ulzd/reproducer+0x10510d) (BuildId: d100254902ddb65c25c4d8ea24192dea2494b7ac)",
    "    #1 0x55555565b4ab in __gnu_cxx::new_allocator<unsigned char>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/ext/new_allocator.h:127:27",
    "    #2 0x55555565b4ab in std::allocator_traits<std::allocator<unsigned char>>::allocate(std::allocator<unsigned char>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/alloc_traits.h:464:20",
    "    #3 0x55555565b4ab in std::_Vector_base<unsigned char, std::allocator<unsigned char>>::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_vector.h:346:20",
    "    #4 0x55555565b4ab in std::_Vector_base<unsigned char, std::allocator<unsigned char>>::_M_create_storage(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_vector.h:361:33",
    "    #5 0x55555565b4ab in std::_Vector_base<unsigned char, std::allocator<unsigned char>>::_Vector_base(unsigned long, std::allocator<unsigned char> const&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_vector.h:305:9",
    "    #6 0x55555565b4ab in std::vector<unsigned char, std::allocator<unsigned char>>::vector(unsigned long, std::allocator<unsigned char> const&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_vector.h:511:9",
    "    #7 0x55555565b4ab in main /tmp/tmpq209ulzd/reproducer.cpp:12:30",
    "    #8 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
    "",
    "SUMMARY: AddressSanitizer: heap-buffer-overflow (/tmp/tmpq209ulzd/reproducer+0xc698f) (BuildId: d100254902ddb65c25c4d8ea24192dea2494b7ac) in __asan_memset",
    "Shadow bytes around the buggy address:",
    "  0x501ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
    "  0x501ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
    "  0x501ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
    "  0x501fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
    "  0x501fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
    "=>0x502000000000: fa fa 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa",
    "  0x502000000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
    "  0x502000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
    "  0x502000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
    "  0x502000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
    "  0x502000000280: 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",
    "==156==ABORTING"
  ],
  "MsanReport": [],
  "UbsanReport": [],
  "LuaReport": [],
  "PythonReport": [],
  "GoReport": [],
  "JavaReport": [],
  "RustReport": [],
  "JsReport": [],
  "CSharpReport": [],
  "CrashLine": "/fuzz/src/trled.c:112:9",
  "Source": [
    "    108          vlget32(ip, r);",
    "    109          if(likely(r) >= 3) {",
    "    110            c   = *ip++;",
    "    111            r  = r-3+4;",
    "--->112            rmemset8(op, c, r);",
    "    113          } else { r++;",
    "    114            rmemset8(op, e, r);",
    "    115          }",
    "    116        }",
    "    117      return ip - in;"
  ]
}

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