I have an msan test that started failing recently because it’s running on an old image without the glibc getrandom wrapper, meaning that Boost was calling syscall(SYS_getrandom, ...)
directly, and clang 16 msan is able to track spot that the output buffer isn’t unpoisoned. (cf. memory sanitizer: not tracking memory initialization with getrandom · Issue #852 · google/sanitizers · GitHub)
Obviously the fix is to upgrade that CI run to a more recent OS image, but it got me to thinking - it shouldn’t be too tricky to write a generic syscall interceptor that invokes the beautifully handwritten pre- and post- hooks in sanitizer_common_syscalls.inc, as suggested here: memory sanitizer: not tracking memory initialization with getrandom · Issue #852 · google/sanitizers · GitHub ? It feels like it would save heartache for people stuck on old libcs.
I hacked up a prototype and it seemed to work without a hitch:
INTERCEPTOR(long, syscall, long number, ...) {
init_syscall();
long arg[6];
std::va_list ap;
va_start(ap, number);
for (int i = 0; i != 6; ++i)
arg[i] = va_arg(ap, long);
va_end(ap);
auto invoke_impl = [&]<std::size_t... I>(auto pre, auto post, std::index_sequence<I...>) {
pre(arg[I]...);
long result = REAL(syscall)(number, arg[I]...);
__msan_unpoison(&result, sizeof result);
post(result, arg[I]...);
return result;
};
auto invoke = [&]<std::same_as<long>... T>(void (*pre)(T...), void (*post)(long result, T...)) {
return invoke_impl(pre, post, std::index_sequence_for<T...>());
};
#define CASE(x) case SYS_ ## x : return invoke(__sanitizer_syscall_pre_impl_ ## x, __sanitizer_syscall_post_impl_ ## x);
switch (number) {
CASE(getrandom)
// etc.
}
__msan_unpoison(arg, sizeof arg); // unknown
long result = REAL(syscall)(number, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
__msan_unpoison(&result, sizeof result);
return result;
}
Is this something that would be working up into a patch?