AddressSanitizer 中的“影子字节”是什么,我应该如何解释它们?

the*_*ian 13 c memory debugging address-sanitizer

我正在调试一个 C 程序,当它发现问题时,我对 AddressSanitizer 输出的下半部分感到非常困惑。例如,让我们使用它:

==33184==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000005 at pc 0x55f312fe2509 bp 0x7ffc99f5f5c0 sp 0x7ffc99f5f5b0
WRITE of size 1 at 0x602000000005 thread T0
    #0 0x55f312fe2508 in main /home/user/c/friends/main.c:20
    #1 0x7fa5ea0e9b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #2 0x55f312fe21c9 in _start (/home/user/c/friends/cmake-build-debug/friends+0x11c9)

0x602000000005 is located 11 bytes to the left of 5-byte region [0x602000000010,0x602000000015)
allocated by thread T0 here:
    #0 0x7fa5eb2b8b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
    #1 0x55f312fe23f4 in main /home/user/c/friends/main.c:18
    #2 0x7fa5ea0e9b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/user/c/friends/main.c:20 in main

  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 05 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
==33184==ABORTING
Run Code Online (Sandbox Code Playgroud)

这条线以上的一切,我明白: SUMMARY: AddressSanitizer: heap-buffer-overflow /home/user/c/friends/main.c:20 in main

我的问题涉及该行下方显示的数据。我阅读了这个答案,但它没有回答我的问题。ASAN 显示的内存转储如下所示:

  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 05 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
Run Code Online (Sandbox Code Playgroud)
  1. 带箭头的线试图告诉我什么?我的假设是05出现在fas之间的是指0x602000000005 is located 11 bytes to the left of 5-byte region“5 字节区域”。不过,我仍然困惑,因为传说中说fa的意思是“堆离开redzone后面,”但它出现在右边05 ,并向左它。为什么没有“堆正确的红区”?

  2. 在这个例子中,ASAN 说程序从 5 字节区域中走了 11 个字节,但它显示的fas远不止这些。

  3. 是否有任何适当的详细文档实际上解释了这些术语“heap left redzone”、“stack mid redzone”、“Global redzone”等的含义?我一直找不到。

  4. 在这种情况下,什么是“影子字节/地址”?

Use*_*ess 21

AddressSanitizer 中的“影子字节”是什么,我应该如何解释它们?

来自GitHub 上的AddressSanitizerAlgorithm页面(也从LLVM AddressSanitizer 页面链接):

虚拟地址空间分为 2 个不相交的类:

  • 主应用程序内存 (Mem):此内存由常规应用程序代码使用。
  • 阴影内存(Shadow):此内存包含阴影值(或元数据)。影子和主应用内存有对应关系。在主内存中中毒一个字节意味着将一些特殊值写入相应的影子内存中。

所以“影子字节”是描述程序可寻址内存状态的元数据。

如果我们查看 asan 输出:

Shadow byte legend (one shadow byte represents 8 application bytes):
Run Code Online (Sandbox Code Playgroud)

它告诉我们 hexdump 是影子内存,它描述了程序“真实”内存的状态。它跟踪哪些状态?

  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  ...
Run Code Online (Sandbox Code Playgroud)

因此,如果整个 8 字节行是可寻址的,则跟踪(或阴影)它的阴影字节应该具有 value 00。如果它是部分可寻址的,则影子字节将为01..07,这可能是该行中可寻址字节的数量。

十六进制转储指向您的值是fa,或“Heap left redzone” - 大概这是堆分配周围的某种保护区域,用于检测溢出。

从同一个链接:

运行时库替换了 malloc 和 free 函数。malloc-ed 区域(红色区域)周围的内存中毒了

更广泛地说,这个描述(在程序地址中)

0x602000000005 is located 11 bytes to the left of 5-byte region
  [0x602000000010,0x602000000015)
Run Code Online (Sandbox Code Playgroud)

匹配显示的阴影贴图:

=>0x0c047fff8000:[fa]fa 05 fa ...
Run Code Online (Sandbox Code Playgroud)

假设自然对齐,

  • 影子字节0x0c047fff8000描述(或再次影子)程序地址0x602000000000..0x602000000007,其中包括您访问的地址
  • 下一个影子字节 at0x0c047fff8001描述程序地址0x602000000008..0x60200000000F
  • 这两个都有价值fa,意思是“堆左红区”
  • 下一个阴影字节在0x0c047fff8002描述程序地址0x602000000010..0x602000000007,并具有值05,这意味着5个字节是可寻址的。这些是堆分配的 5 个字节。

所有这些都与您确实理解的错误部分一致。

  1. 不过,我仍然困惑,因为传说中说发来“堆离开redzone后面,”但它出现在右边05 ,并向左它。为什么没有“堆正确的红区”?

    我不知道方向性的真正含义,在这里。堆最初通常在一个方向上增长(传统上随着堆栈的增长而增长),但可以分片、释放、合并和重新分配。两个分配之间的间隔是“右”还是“左”,或两者兼而有之,或者两者都不是?我们需要知道的是,这是一个从未分配给用户的中毒堆区域。

    如果没有与堆栈左/中/右值相对应的方向,也许它应该只是“堆红区”。

  2. 在这个例子中,ASAN 说程序从 5 字节区域中走了 11 个字节,但它显示的 fas 远不止于此。

    fa正如图例所说,每个代表八个字节。因此,如果您在分配之前访问了 9 到 15 个字节的任何内容(模算术错误),它就会出现在同一个影子字节中。如果您之前访问过 1 到 8 个字节,它将显示在下一个影子字节中(就在 之前05)。

    其余的fas 只是周围区域的地图,在这种情况下似乎没有帮助,但在其他情况下可能有用。

  3. 是否有任何适当的详细文档实际上解释了这些术语“heap left redzone”、“stack mid redzone”、“Global redzone”等的含义?

    不知道。不过,它们似乎很自然地从用例中遵循——你击中了一个红色区域 = 你访问了一个你不应该访问的地址。您可以随时阅读代码,例如。asan_internal.h定义kAsanHeapLeftRedzoneMagic值,并asan_allocator.cpp用它毒化影子字节。

  4. 在这种情况下,什么是“影子字节/地址”?

    为了完整起见,影子字节是一个字节,它对一组八个通常可访问的程序字节进行屏蔽,并跟踪有关它们的一些对消毒剂有用的信息。

    影子地址是影子字节的地址。

  • 不用担心,这不是一场比赛:) (2认同)