Skip to content

[sanitizer_common] Fix edge case for stack mapping parsing #98381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 10, 2024

Conversation

thurstond
Copy link
Contributor

@thurstond thurstond commented Jul 10, 2024

On some systems (e.g., at least two AArch64 Linux instances), the process map can have:

    fffffffdf000-1000000000000 ... [stack]

instead of:

    fffffffdf000- ffffffffffff

The stack top value is larger than GetMaxUserVirtualAddress(), which violates the precondition that shadow memory calculations expect. This patch fixes the issue by saturating off-by-one values (and also adds checks for more flagrant violations).

This fixes an issue that was observed with DFSan on AArch64 Linux (with high-entropy ASLR, resulting in ASLR being disabled on some runs):

==11057==ERROR: DataflowSanitizer failed to allocate 0x1600000800000 (387028101365760) bytes at address 4fffff800000 (errno: 12)

(https://lab.llvm.org/staging/#/builders/90/builds/552/steps/9/logs/stdio) This was trying to allocate a shadow at [0x4fffff800000, 0x4fffff800000 + 0x1600000800000] = [0x4fffff800000, 0x1b00000000000]. Notice that the end of the shadow region - an invalid value - is equal to MEM_TO_SHADOW(0x1000000000000), where MEM_TO_SHADOW is defined as (mem ^ 0xB00000000000ULL).

On some systems (e.g., at least two AArch64 Linux instances), the process map can have:
    fffffffdf000-1000000000000 ... [stack]
instead of:
    fffffffdf000- ffffffffffff
The stack top value is larger than GetMaxUserVirtualAddress(), which violates the precondition
that shadow memory calculations expect. This patch fixes the issue by saturating off-by-one values (and also
adds checks for more flagrant violations).

This fixes an issue that was observed with DFSan on AArch64 Linux (with high-entropy ASLR, resulting in ASLR being disabled on some runs):
```
==11057==ERROR: DataflowSanitizer failed to allocate 0x1600000800000 (387028101365760) bytes at address 4fffff800000 (errno: 12)
```
(https://lab.llvm.org/staging/#/builders/90/builds/552/steps/9/logs/stdio)
This was trying to allocate a shadow at [0x4fffff800000, 0x4fffff800000 + 0x1600000800000]
= [0x4fffff800000, 0x1b00000000000]. Notice that the end of the shadow region is equal to
MEM_TO_SHADOW(0x1000000000000), where MEM_TO_SHADOW is defined as (mem ^ 0xB00000000000ULL).
@llvmbot
Copy link
Member

llvmbot commented Jul 10, 2024

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Thurston Dang (thurstond)

Changes

On some systems (e.g., at least two AArch64 Linux instances), the process map can have:
fffffffdf000-1000000000000 ... [stack]
instead of:
fffffffdf000- ffffffffffff
The stack top value is larger than GetMaxUserVirtualAddress(), which violates the precondition that shadow memory calculations expect. This patch fixes the issue by saturating off-by-one values (and also adds checks for more flagrant violations).

This fixes an issue that was observed with DFSan on AArch64 Linux (with high-entropy ASLR, resulting in ASLR being disabled on some runs):

==11057==ERROR: DataflowSanitizer failed to allocate 0x1600000800000 (387028101365760) bytes at address 4fffff800000 (errno: 12)

(https://lab.llvm.org/staging/#/builders/90/builds/552/steps/9/logs/stdio) This was trying to allocate a shadow at [0x4fffff800000, 0x4fffff800000 + 0x1600000800000] = [0x4fffff800000, 0x1b00000000000]. Notice that the end of the shadow region is equal to MEM_TO_SHADOW(0x1000000000000), where MEM_TO_SHADOW is defined as (mem ^ 0xB00000000000ULL).


Full diff: https://github.com/llvm/llvm-project/pull/98381.diff

1 Files Affected:

  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp (+13)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
index 175362183fd78..f902ffaae2eff 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -149,6 +149,19 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
       stacksize = kMaxThreadStackSize;
     *stack_top = segment.end;
     *stack_bottom = segment.end - stacksize;
+
+    uptr maxAddr = GetMaxUserVirtualAddress();
+    // Edge case: the stack mapping on some systems may be off-by-one e.g.,
+    //     fffffffdf000-1000000000000 rw-p 00000000 00:00 0 [stack]
+    // instead of:
+    //     fffffffdf000- ffffffffffff
+    // The out-of-range stack_top can result in an invalid shadow address
+    // calculation, since those usually assume the parameters are in range.
+    if (*stack_top == maxAddr + 1)
+      *stack_top = maxAddr;
+    else
+      CHECK_LT(*stack_top, maxAddr);
+
     return;
   }
   uptr stacksize = 0;

@vitalybuka vitalybuka merged commit 694b132 into llvm:main Jul 10, 2024
4 of 5 checks passed
aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
On some systems (e.g., at least two AArch64 Linux instances), the
process map can have:
```
    fffffffdf000-1000000000000 ... [stack]
```
instead of:
```
    fffffffdf000- ffffffffffff
```
The stack top value is larger than `GetMaxUserVirtualAddress()`, which
violates the precondition that shadow memory calculations expect. This
patch fixes the issue by saturating off-by-one values (and also adds
checks for more flagrant violations).

This fixes an issue that was observed with DFSan on AArch64 Linux (with
high-entropy ASLR, resulting in ASLR being disabled on some runs):
```
==11057==ERROR: DataflowSanitizer failed to allocate 0x1600000800000 (387028101365760) bytes at address 4fffff800000 (errno: 12)
```

(https://lab.llvm.org/staging/#/builders/90/builds/552/steps/9/logs/stdio)
This was trying to allocate a shadow at `[0x4fffff800000, 0x4fffff800000
+ 0x1600000800000] = [0x4fffff800000, 0x1b00000000000]`. Notice that the
end of the shadow region - an invalid value - is equal to
`MEM_TO_SHADOW(0x1000000000000)`, where `MEM_TO_SHADOW` is defined as
`(mem ^ 0xB00000000000ULL)`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants