当一切看起来都正常时,为什么这是堆缓冲区溢出?

问题描述 投票:0回答:1

当我在 clang 中使用 Fuzzer 和 Adresssanitizer 并针对

memcpy
进行测试时,两者都报告堆缓冲区溢出,但我无法解释自己实际上“为什么”。在名为
foo
的虚拟函数中,我创建了一个名为
buf
的缓冲区,大小为 4 个字节。函数 foo 接受一个名为
str
的参数,顾名思义,它应该包含一个字符串。在此示例中,我将字符串“hello”传递给 foo。由于 buf 中只有 4 个字节,我还指示 memcpy 始终只从参数 str 中复制 4 个字节,否则我们会溢出。

但是,为什么 Clang fuzzer/AdressSanitizer 会报告堆溢出?对我来说一切似乎都很好...我从一个较大的字符串(“hello”)仅复制 4 个字节到一个缓冲区(buf),无论如何它只能容纳 4 个字节..

要创建错误,这是源文件

fuzz_string.cpp

#include <string>
#include <cstdint>
#include <cstring>


int foo(const char *str)
{
    char    buf[4];

    memcpy(buf, str, sizeof(buf));

    return 0;
}


extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    foo(reinterpret_cast<const char*>(data));
    return 0;
}

编译:

clang++ -g -fsanitize=address,fuzzer fuzz_string.cpp -o fuzz_string

还创建一个名为

corpus/
的子目录,并在其中放置一个名为
input1
的文件,其中包含:

hello

之后我通过运行以下命令来执行程序:

./fuzz_string corpus -max_len=1000
输出:

./fuzz_string corpus -max_len=1000
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3852592942
INFO: Loaded 1 modules   (2 inline 8-bit counters): 2 [0x558e0d7deed0, 0x558e0d7deed2),
INFO: Loaded 1 PC tables (2 PCs): 2 [0x558e0d7deed8,0x558e0d7deef8),
INFO:        1 files found in corpus
=================================================================
==3433==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000011 at pc 0x558e0d79bf20 bp 0x7ffeb3a6b750 sp 0x7ffeb3a6b748
READ of size 1 at 0x602000000011 thread T0
    #0 0x558e0d79bf1f in foo(char const*) /mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string.cpp:19:14
    #1 0x558e0d79c160 in LLVMFuzzerTestOneInput /mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string.cpp:30:5
    #2 0x558e0d6c2323 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x3e323) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #3 0x558e0d6c3580 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile> >&) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x3f580) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #4 0x558e0d6c3bd2 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile> >&) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x3fbd2) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #5 0x558e0d6b1f22 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x2df22) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #6 0x558e0d6dbc12 in main (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x57c12) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #7 0x7ff7481b6d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 203de0ae33b53fee1578b117cb4123e85d0534f0)
    #8 0x7ff7481b6e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 203de0ae33b53fee1578b117cb4123e85d0534f0)
    #9 0x558e0d6a6964 in _start (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x22964) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)

0x602000000011 is located 0 bytes to the right of 1-byte region [0x602000000010,0x602000000011)
allocated by thread T0 here:
    #0 0x558e0d79985d in operator new[](unsigned long) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x11585d) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #1 0x558e0d6c2232 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x3e232) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #2 0x558e0d6c3580 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile> >&) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x3f580) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #3 0x558e0d6c3bd2 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile> >&) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x3fbd2) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #4 0x558e0d6b1f22 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x2df22) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #5 0x558e0d6dbc12 in main (/mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string+0x57c12) (BuildId: b5f5fad80b257a1e799c54575adef93091b807c4)
    #6 0x7ff7481b6d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 203de0ae33b53fee1578b117cb4123e85d0534f0)

SUMMARY: AddressSanitizer: heap-buffer-overflow /mnt/c/Users/masch/Documents/Workbench/C/nexus-src/fuzz_string.cpp:19:14 in foo(char const*)
Shadow bytes around the buggy address:
  0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa[01]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: 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
==3433==ABORTING
MS: 0 ; base unit: 0000000000000000000000000000000000000000


artifact_prefix='./'; Test unit written to ./crash-da39a3ee5e6b4b0d3255bfef95601890afd80709
Base64:

我尝试在谷歌上搜索示例或解释,但不幸的是,没有人能帮助我。这个链接让我对这个主题感到好奇,但无法正确解释为什么当我们仅将 4 字节复制到 4 字节目标时会导致堆溢出。

c++ c security buffer overflow
1个回答
1
投票

如果 strlen(str) < 3. I suggest you use

strncpy()
则代码将会溢出,并确保
buf
如果您需要它是一个字符串,则以“ ”结尾。

if(str)
  memcpy(buf, str, strlen(str) < 3 ? strtlen(str) + 1 : sizeof(buf));

如果

str
不是字符串(给定调用者传入
size_t
),则无法在
foo()
中修复此问题。

© www.soinside.com 2019 - 2024. All rights reserved.