virnetserver: handle sigaction correctly

POSIX says that sa_sigaction is only safe to use if sa_flags
includes SA_SIGINFO; conversely, sa_handler is only safe to
use when flags excludes that bit.  Gnulib doesn't guarantee
an implementation of SA_SIGINFO, but does guarantee that
if SA_SIGINFO is undefined, we can safely define it to 0 as
long as we don't dereference the 2nd or 3rd argument of
any handler otherwise registered via sa_sigaction.

Based on a report by Wen Congyang.

* src/rpc/virnetserver.c (SA_SIGINFO): Stub for mingw.
(virNetServerSignalHandler): Avoid bogus dereference.
(virNetServerFatalSignal, virNetServerNew): Set flags properly.
(virNetServerAddSignalHandler): Drop unneeded #ifdef.
This commit is contained in:
Eric Blake 2012-04-19 21:41:27 -06:00 committed by Cole Robinson
parent 8a55d381ae
commit ac620c2e4a

View File

@ -1,7 +1,7 @@
/* /*
* virnetserver.c: generic network RPC server * virnetserver.c: generic network RPC server
* *
* Copyright (C) 2006-2011 Red Hat, Inc. * Copyright (C) 2006-2012 Red Hat, Inc.
* Copyright (C) 2006 Daniel P. Berrange * Copyright (C) 2006 Daniel P. Berrange
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
@ -43,6 +43,10 @@
# include <dbus/dbus.h> # include <dbus/dbus.h>
#endif #endif
#ifndef SA_SIGINFO
# define SA_SIGINFO 0
#endif
#define VIR_FROM_THIS VIR_FROM_RPC #define VIR_FROM_THIS VIR_FROM_RPC
#define virNetError(code, ...) \ #define virNetError(code, ...) \
virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \
@ -277,8 +281,9 @@ error:
} }
static void virNetServerFatalSignal(int sig, siginfo_t *siginfo ATTRIBUTE_UNUSED, static void
void *context ATTRIBUTE_UNUSED) virNetServerFatalSignal(int sig, siginfo_t *siginfo ATTRIBUTE_UNUSED,
void *context ATTRIBUTE_UNUSED)
{ {
struct sigaction sig_action; struct sigaction sig_action;
int origerrno; int origerrno;
@ -293,6 +298,7 @@ static void virNetServerFatalSignal(int sig, siginfo_t *siginfo ATTRIBUTE_UNUSED
#ifdef SIGUSR2 #ifdef SIGUSR2
if (sig != SIGUSR2) { if (sig != SIGUSR2) {
#endif #endif
memset(&sig_action, 0, sizeof(sig_action));
sig_action.sa_handler = SIG_DFL; sig_action.sa_handler = SIG_DFL;
sigaction(sig, &sig_action, NULL); sigaction(sig, &sig_action, NULL);
raise(sig); raise(sig);
@ -390,6 +396,7 @@ virNetServerPtr virNetServerNew(size_t min_workers,
* debugging purposes or testing * debugging purposes or testing
*/ */
sig_action.sa_sigaction = virNetServerFatalSignal; sig_action.sa_sigaction = virNetServerFatalSignal;
sig_action.sa_flags = SA_SIGINFO;
sigaction(SIGFPE, &sig_action, NULL); sigaction(SIGFPE, &sig_action, NULL);
sigaction(SIGSEGV, &sig_action, NULL); sigaction(SIGSEGV, &sig_action, NULL);
sigaction(SIGILL, &sig_action, NULL); sigaction(SIGILL, &sig_action, NULL);
@ -455,17 +462,24 @@ static sig_atomic_t sigErrors = 0;
static int sigLastErrno = 0; static int sigLastErrno = 0;
static int sigWrite = -1; static int sigWrite = -1;
static void virNetServerSignalHandler(int sig, siginfo_t * siginfo, static void
void* context ATTRIBUTE_UNUSED) virNetServerSignalHandler(int sig, siginfo_t * siginfo,
void* context ATTRIBUTE_UNUSED)
{ {
int origerrno; int origerrno;
int r; int r;
siginfo_t tmp;
if (SA_SIGINFO)
tmp = *siginfo;
else
memset(&tmp, 0, sizeof(tmp));
/* set the sig num in the struct */ /* set the sig num in the struct */
siginfo->si_signo = sig; tmp.si_signo = sig;
origerrno = errno; origerrno = errno;
r = safewrite(sigWrite, siginfo, sizeof(*siginfo)); r = safewrite(sigWrite, &tmp, sizeof(tmp));
if (r == -1) { if (r == -1) {
sigErrors++; sigErrors++;
sigLastErrno = errno; sigLastErrno = errno;
@ -568,9 +582,7 @@ int virNetServerAddSignalHandler(virNetServerPtr srv,
memset(&sig_action, 0, sizeof(sig_action)); memset(&sig_action, 0, sizeof(sig_action));
sig_action.sa_sigaction = virNetServerSignalHandler; sig_action.sa_sigaction = virNetServerSignalHandler;
#ifdef SA_SIGINFO
sig_action.sa_flags = SA_SIGINFO; sig_action.sa_flags = SA_SIGINFO;
#endif
sigemptyset(&sig_action.sa_mask); sigemptyset(&sig_action.sa_mask);
sigaction(signum, &sig_action, &sigdata->oldaction); sigaction(signum, &sig_action, &sigdata->oldaction);