hostip: Fix signal race in Curl_resolv_timeout.

A signal handler for SIGALRM is installed in Curl_resolv_timeout. It is
configured to interrupt system calls and uses siglongjmp to return into
the function if alarm() goes off.

The signal handler is installed before curl_jmpenv is initialized.
This means that an already installed alarm timer could trigger the
newly installed signal handler, leading to undefined behavior when it
accesses the uninitialized curl_jmpenv.

Even if there is no previously installed alarm available, the code in
Curl_resolv_timeout itself installs an alarm before the environment is
fully set up. If the process is sent into suspend right after that, the
signal handler could be called too early as in previous scenario.

To fix this, the signal handler should only be installed and the alarm
timer only be set after sigsetjmp has been called.
This commit is contained in:
Tobias Stoeckmann 2015-03-14 14:32:42 +01:00 committed by Daniel Stenberg
parent 0cf649d9cc
commit 851c29269b

View File

@ -607,6 +607,19 @@ int Curl_resolv_timeout(struct connectdata *conn,
we want to wait less than one second we must bail out already now. */
return CURLRESOLV_TIMEDOUT;
/* This allows us to time-out from the name resolver, as the timeout
will generate a signal and we will siglongjmp() from that here.
This technique has problems (see alarmfunc).
This should be the last thing we do before calling Curl_resolv(),
as otherwise we'd have to worry about variables that get modified
before we invoke Curl_resolv() (and thus use "volatile"). */
if(sigsetjmp(curl_jmpenv, 1)) {
/* this is coming from a siglongjmp() after an alarm signal */
failf(data, "name lookup timed out");
rc = CURLRESOLV_ERROR;
goto clean_up;
}
else {
/*************************************************************
* Set signal handler to catch SIGALRM
* Store the old value to be able to set it back later!
@ -632,18 +645,6 @@ int Curl_resolv_timeout(struct connectdata *conn,
/* alarm() makes a signal get sent when the timeout fires off, and that
will abort system calls */
prev_alarm = alarm(curlx_sltoui(timeout/1000L));
/* This allows us to time-out from the name resolver, as the timeout
will generate a signal and we will siglongjmp() from that here.
This technique has problems (see alarmfunc).
This should be the last thing we do before calling Curl_resolv(),
as otherwise we'd have to worry about variables that get modified
before we invoke Curl_resolv() (and thus use "volatile"). */
if(sigsetjmp(curl_jmpenv, 1)) {
/* this is coming from a siglongjmp() after an alarm signal */
failf(data, "name lookup timed out");
rc = CURLRESOLV_ERROR;
goto clean_up;
}
#else