llvm / llvm/llvm-project

[compiler-rt][sanitizer] mmap/munmap/mprotect syscall hooks don't do shadow teardown (unlike the libc interceptors)

Open
#206,978 1 comment 0 reactions 0 assignees View on GitHub
libc
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

# Background

We maintain a C++ codebase that deliberately bypasses glibc and issues raw Linux syscalls via inline asm.

To preserve sanitizer coverage that we'd otherwise get "for free" from the libc interceptors, we've been invoking the `__sanitizer_syscall_pre_*` / `__sanitizer_syscall_post_` hooks from [](https://github.com/llvm/llvm-project/blob/release/20.x/compiler-rt/include/sanitizer/linux_syscall_hooks.h) around each raw syscall (e.g. Man un-poisoning of output buffers after read, etc.).

# The Issue

My understanding is, that this scenario (doing raw syscalls) is something that is ~supported and where hooks could be used, which is briefly supported by related issues [#114641,#114377,#111847], and discussion in [[1](https://discourse.llvm.org/t/how-does-sanitizer-common-syscalls-inc-work/82941/4)].

However, it seems that we've found some of the hooks are not equivalent with real intercepts. As an example consider the memory-mapping syscalls

In [sanitizer_common/sanitizer_common_syscalls.inc](https://github.com/llvm/llvm-project/blob/release/20.x/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc), [POST_SYSCALL(munmap)](https://github.com/llvm/llvm-project/blob/release/20.x/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc#L1233) (and the mmap/mprotect variants) are empty, so a raw munmap followed by `__sanitizer_syscall_post_impl_munmap` leaves the ASan shadow for the unmapped range still poisoned, whereas routing the same call through the libc munmap interceptor tears the shadow down (matching glibc), see [sanitizer_common/sanitizer_common_interceptors.inc#L7625](https://github.com/llvm/llvm-project/blob/release/20.x/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc#L7625) and
[asan/asan_interceptors.cpp#L188](https://github.com/llvm/llvm-project/blob/release/20.x/compiler-rt/lib/asan/asan_interceptors.cpp#L188) and
[asan/asan_interceptors.cpp#L176](https://github.com/llvm/llvm-project/blob/release/20.x/compiler-rt/lib/asan/asan_interceptors.cpp#L176).

# Reproducer

We can reproduce this in a few lines: poison a page, unmap it via raw syscall + the pre/post-hooks, and `__asan_region_is_poisoned` still seems to report the range poisoned, only the interceptor path clears it. It is likely same/similar gap applies to other sanitizers (e.g. TSan's shadow `UnmapShadow`)

# Questions

So, my main questions are:
1. Is the empty `munmap`/`mmap`/`mprotect` post-hook intentional (i.e. is shadow teardown deliberately out of scope for the syscall-hook layer) or is it an oversight?
2. If we genuinely cannot/don't want to route through libc, what's the recommended way to get correct shadow teardown for these syscalls? (since unmapping shadows does not seem to be public API of the sanitizers)

# Extra Links

[1] https://discourse.llvm.org/t/how-does-sanitizer-common-syscalls-inc-work/82941/4

Contributor guide

Open the contributing guide

Research direction

Start with compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc, especially POST_SYSCALL(munmap), mmap, and mprotect, then compare them with sanitizer_common/sanitizer_common_interceptors.inc and compiler-rt/lib/asan/asan_interceptors.cpp. Reproduce the raw-syscall case described in the issue and inspect the sanitizer behavior; done means the intended hook contract and supported way to obtain correct shadow teardown are established, with any needed behavior covered by a regression test.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, linux
Domain
compilers, operating-systems, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.