[compiler-rt] 23ead65 - [compiler-rt][sanitizer_common] Fix setgroups syscall pre-hook to check its input (#209207)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 12:54:13 PDT 2026
Author: Patrik Dokoupil
Date: 2026-07-15T19:54:08Z
New Revision: 23ead65310da314ae04a1c30137f279beaac1a4f
URL: https://github.com/llvm/llvm-project/commit/23ead65310da314ae04a1c30137f279beaac1a4f
DIFF: https://github.com/llvm/llvm-project/commit/23ead65310da314ae04a1c30137f279beaac1a4f.diff
LOG: [compiler-rt][sanitizer_common] Fix setgroups syscall pre-hook to check its input (#209207)
# About
`PRE_SYSCALL(setgroups)`/`setgroups16` called `POST_WRITE` on their
`grouplist` argument, but grouplist is a read-only input the kernel
never writes. Under MSan, `POST_WRITE` maps to `__msan_unpoison`, so
annotating a raw setgroups(2) via the documented
`__sanitizer_syscall_pre_setgroups` hook silently marked an
uninitialized group list as initialized -- before the syscall even ran,
and even on failure -- masking a real use-of-uninitialized-value bug.
Under TSan it recorded a write range where a read belongs.
Use PRE_READ, matching every other input-only argument in this file
(e.g. sched_setparam). Add an MSan regression test.
Added:
compiler-rt/test/msan/Linux/syscalls_setgroups.cpp
Modified:
compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
Removed:
################################################################################
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
index ee3ac723e3669..5f8f840accbf2 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -417,7 +417,7 @@ POST_SYSCALL(setsid)(long res) {}
PRE_SYSCALL(setgroups)(long gidsetsize, __sanitizer___kernel_gid_t *grouplist) {
if (grouplist)
- POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist));
+ PRE_READ(grouplist, gidsetsize * sizeof(*grouplist));
}
POST_SYSCALL(setgroups)
@@ -1663,7 +1663,7 @@ POST_SYSCALL(getgroups16)
PRE_SYSCALL(setgroups16)
(long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) {
if (grouplist)
- POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist));
+ PRE_READ(grouplist, gidsetsize * sizeof(*grouplist));
}
POST_SYSCALL(setgroups16)
diff --git a/compiler-rt/test/msan/Linux/syscalls_setgroups.cpp b/compiler-rt/test/msan/Linux/syscalls_setgroups.cpp
new file mode 100644
index 0000000000000..b7b08e630f36b
--- /dev/null
+++ b/compiler-rt/test/msan/Linux/syscalls_setgroups.cpp
@@ -0,0 +1,31 @@
+// RUN: %clangxx_msan -DPRE1 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <string.h>
+
+#include <sanitizer/linux_syscall_hooks.h>
+#include <sanitizer/msan_interface.h>
+
+// The setgroups pre-hook must READ (check) its input group list, not write to
+// (unpoison) it: grouplist is a pure input the kernel only reads. Passing an
+// uninitialized list is a caller-side bug the pre-hook must report.
+int main() {
+ unsigned int groups[4];
+
+#if defined(PRE1)
+ // Uninitialized input -> the pre-hook must report use-of-uninitialized-value.
+ __msan_poison(groups, sizeof(groups));
+ __sanitizer_syscall_pre_setgroups(4, groups);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+#else
+ // A fully-initialized input is fine: no report, and the hook must not
+ // unpoison caller memory.
+ memset(groups, 0, sizeof(groups));
+ __sanitizer_syscall_pre_setgroups(4, groups);
+ __sanitizer_syscall_post_setgroups(0, 4, groups);
+ // ...and a clean input stays clean: the hooks must not corrupt its shadow.
+ assert(__msan_test_shadow(groups, sizeof(groups)) == -1);
+#endif
+ return 0;
+}
More information about the llvm-commits
mailing list