forked from OSchip/llvm-project
[msan] Check sigset_t and sigaction arguments.
Summary: Check sigset_t arguments in ppoll, sig*wait*, sigprocmask interceptors, and the entire "struct sigaction" in sigaction. This can be done because sigemptyset/sigfullset are intercepted and signal masks should be correctly marked as initialized. Reviewers: vitalybuka Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D37367 llvm-svn: 312576
This commit is contained in:
parent
32504cf661
commit
8b80b328d1
|
|
@ -983,11 +983,21 @@ static void SignalAction(int signo, void *si, void *uc) {
|
|||
cb(signo, si, uc);
|
||||
}
|
||||
|
||||
static void read_sigaction(const __sanitizer_sigaction *act) {
|
||||
CHECK_UNPOISONED(&act->sa_flags, sizeof(act->sa_flags));
|
||||
if (act->sa_flags & __sanitizer::sa_siginfo)
|
||||
CHECK_UNPOISONED(&act->sigaction, sizeof(act->sigaction));
|
||||
else
|
||||
CHECK_UNPOISONED(&act->handler, sizeof(act->handler));
|
||||
CHECK_UNPOISONED(&act->sa_mask, sizeof(act->sa_mask));
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
|
||||
__sanitizer_sigaction *oldact) {
|
||||
ENSURE_MSAN_INITED();
|
||||
// FIXME: check that *act is unpoisoned.
|
||||
// That requires intercepting all of sigemptyset, sigfillset, etc.
|
||||
if (act) read_sigaction(act);
|
||||
int res;
|
||||
if (flags()->wrap_signals) {
|
||||
SpinMutexLock lock(&sigactions_mu);
|
||||
|
|
|
|||
|
|
@ -3589,7 +3589,7 @@ INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
|
|||
if (fds && nfds) read_pollfd(ctx, fds, nfds);
|
||||
if (timeout_ts)
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz);
|
||||
// FIXME: read sigmask when all of sigemptyset, etc are intercepted.
|
||||
if (sigmask) COMMON_INTERCEPTOR_READ_RANGE(ctx, sigmask, sizeof(*sigmask));
|
||||
int res =
|
||||
COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask);
|
||||
if (fds && nfds) write_pollfd(ctx, fds, nfds);
|
||||
|
|
@ -3630,7 +3630,7 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
|
|||
INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, sig);
|
||||
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
|
||||
if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
|
||||
// FIXME: under ASan the call below may write to freed memory and corrupt
|
||||
// its metadata. See
|
||||
// https://github.com/google/sanitizers/issues/321.
|
||||
|
|
@ -3647,7 +3647,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
|
|||
INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, info);
|
||||
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
|
||||
if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
|
||||
// FIXME: under ASan the call below may write to freed memory and corrupt
|
||||
// its metadata. See
|
||||
// https://github.com/google/sanitizers/issues/321.
|
||||
|
|
@ -3666,7 +3666,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
|
|||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout);
|
||||
if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz);
|
||||
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
|
||||
if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
|
||||
// FIXME: under ASan the call below may write to freed memory and corrupt
|
||||
// its metadata. See
|
||||
// https://github.com/google/sanitizers/issues/321.
|
||||
|
|
@ -3729,7 +3729,7 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
|
|||
__sanitizer_sigset_t *oldset) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset);
|
||||
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
|
||||
if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
|
||||
// FIXME: under ASan the call below may write to freed memory and corrupt
|
||||
// its metadata. See
|
||||
// https://github.com/google/sanitizers/issues/321.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
// RUN: %clangxx_msan -O0 -std=c++11 -g %s -o %t
|
||||
// RUN: %run %t _ 2>&1 | FileCheck %s --check-prefix=CLEAN
|
||||
// RUN: not %run %t A 2>&1 | FileCheck %s --check-prefix=A
|
||||
// RUN: not %run %t B 2>&1 | FileCheck %s --check-prefix=B
|
||||
|
||||
#include <assert.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sanitizer/msan_interface.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char T = argv[1][0];
|
||||
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000;
|
||||
int res = ppoll(nullptr, 0, &ts, nullptr);
|
||||
assert(res == 0);
|
||||
|
||||
if (T == 'A') {
|
||||
__msan_poison(&ts.tv_sec, sizeof(ts.tv_sec));
|
||||
ppoll(nullptr, 0, &ts, nullptr);
|
||||
// A: use-of-uninitialized-value
|
||||
}
|
||||
|
||||
// A-NOT: ==1
|
||||
// B: ==1
|
||||
fprintf(stderr, "==1\n");
|
||||
|
||||
sigset_t sig;
|
||||
if (T != 'B')
|
||||
sigemptyset(&sig);
|
||||
ppoll(nullptr, 0, &ts, &sig);
|
||||
// B: use-of-uninitialized-value
|
||||
|
||||
// B-NOT: ==2
|
||||
// CLEAN: ==2
|
||||
fprintf(stderr, "==2\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t
|
||||
// RUN: %run %t __
|
||||
// RUN: not %run %t A_ 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t AH 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t B_ 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t BH 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t C_ 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t CH 2>&1 | FileCheck %s
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sanitizer/msan_interface.h>
|
||||
|
||||
void handler(int) {}
|
||||
void action(int, siginfo_t *, void *) {}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char T = argv[1][0];
|
||||
char H = argv[1][1];
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
if (H == 'H') {
|
||||
sa.sa_handler = handler;
|
||||
} else {
|
||||
sa.sa_sigaction = action;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
}
|
||||
|
||||
if (T == 'A') {
|
||||
if (H == 'H')
|
||||
__msan_poison(&sa.sa_handler, sizeof(sa.sa_handler));
|
||||
else
|
||||
__msan_poison(&sa.sa_sigaction, sizeof(sa.sa_sigaction));
|
||||
}
|
||||
if (T == 'B')
|
||||
__msan_poison(&sa.sa_flags, sizeof(sa.sa_flags));
|
||||
if (T == 'C')
|
||||
__msan_poison(&sa.sa_mask, sizeof(sa.sa_mask));
|
||||
// CHECK: use-of-uninitialized-value
|
||||
int res = sigaction(SIGUSR1, &sa, nullptr);
|
||||
assert(res == 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,16 +1,21 @@
|
|||
// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t
|
||||
// RUN: %clangxx_msan -DPOSITIVE -std=c++11 -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
#include <assert.h>
|
||||
#include <sanitizer/msan_interface.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sanitizer/msan_interface.h>
|
||||
|
||||
void test_sigwait() {
|
||||
sigset_t s;
|
||||
#ifndef POSITIVE
|
||||
sigemptyset(&s);
|
||||
sigaddset(&s, SIGUSR1);
|
||||
#endif
|
||||
sigprocmask(SIG_BLOCK, &s, 0);
|
||||
// CHECK: MemorySanitizer: use-of-uninitialized-value
|
||||
|
||||
if (pid_t pid = fork()) {
|
||||
kill(pid, SIGUSR1);
|
||||
|
|
|
|||
Loading…
Reference in New Issue