[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