1
0
mirror of https://github.com/moparisthebest/curl synced 2025-03-01 09:51:46 -05:00

Curl_pgrsTime - return new time to avoid timeout integer overflow

Setting a timeout to INT_MAX could cause an immediate error to get
returned as timeout because of an overflow when different values of
'now' were used.

This is primarily fixed by having Curl_pgrsTime() return the "now" when
TIMER_STARTSINGLE is set so that the parent function will continue using
that time.

Reported-by: Ionuț-Francisc Oancea
Fixes #5583
Closes #5847
This commit is contained in:
Daniel Stenberg 2020-08-24 11:07:59 +02:00
parent 68a5132474
commit a2c85bb8e4
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
4 changed files with 27 additions and 23 deletions

View File

@ -1317,10 +1317,9 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
const struct Curl_dns_entry *remotehost) const struct Curl_dns_entry *remotehost)
{ {
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
struct curltime before = Curl_now();
CURLcode result = CURLE_COULDNT_CONNECT; CURLcode result = CURLE_COULDNT_CONNECT;
int i; int i;
timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE); timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) { if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */ /* a precaution, no need to continue if time already is up */

View File

@ -1702,7 +1702,7 @@ CURLcode Curl_preconnect(struct Curl_easy *data)
static CURLMcode multi_runsingle(struct Curl_multi *multi, static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct curltime now, struct curltime *nowp,
struct Curl_easy *data) struct Curl_easy *data)
{ {
struct Curl_message *msg = NULL; struct Curl_message *msg = NULL;
@ -1743,7 +1743,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
(data->mstate < CURLM_STATE_COMPLETED)) { (data->mstate < CURLM_STATE_COMPLETED)) {
/* we need to wait for the connect state as only then is the start time /* we need to wait for the connect state as only then is the start time
stored, but we must not check already completed handles */ stored, but we must not check already completed handles */
timeout_ms = Curl_timeleft(data, &now, timeout_ms = Curl_timeleft(data, nowp,
(data->mstate <= CURLM_STATE_DO)? (data->mstate <= CURLM_STATE_DO)?
TRUE:FALSE); TRUE:FALSE);
@ -1752,25 +1752,25 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(data->mstate == CURLM_STATE_WAITRESOLVE) if(data->mstate == CURLM_STATE_WAITRESOLVE)
failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds", " milliseconds",
Curl_timediff(now, data->progress.t_startsingle)); Curl_timediff(*nowp, data->progress.t_startsingle));
else if(data->mstate == CURLM_STATE_WAITCONNECT) else if(data->mstate == CURLM_STATE_WAITCONNECT)
failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds", " milliseconds",
Curl_timediff(now, data->progress.t_startsingle)); Curl_timediff(*nowp, data->progress.t_startsingle));
else { else {
struct SingleRequest *k = &data->req; struct SingleRequest *k = &data->req;
if(k->size != -1) { if(k->size != -1) {
failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
CURL_FORMAT_CURL_OFF_T " bytes received", CURL_FORMAT_CURL_OFF_T " bytes received",
Curl_timediff(now, data->progress.t_startsingle), Curl_timediff(*nowp, data->progress.t_startsingle),
k->bytecount, k->size); k->bytecount, k->size);
} }
else { else {
failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds with %" CURL_FORMAT_CURL_OFF_T " milliseconds with %" CURL_FORMAT_CURL_OFF_T
" bytes received", " bytes received",
Curl_timediff(now, data->progress.t_startsingle), Curl_timediff(*nowp, data->progress.t_startsingle),
k->bytecount); k->bytecount);
} }
} }
@ -1795,7 +1795,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(!result) { if(!result) {
/* after init, go CONNECT */ /* after init, go CONNECT */
multistate(data, CURLM_STATE_CONNECT); multistate(data, CURLM_STATE_CONNECT);
Curl_pgrsTime(data, TIMER_STARTOP); *nowp = Curl_pgrsTime(data, TIMER_STARTOP);
rc = CURLM_CALL_MULTI_PERFORM; rc = CURLM_CALL_MULTI_PERFORM;
} }
break; break;
@ -1812,7 +1812,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(result) if(result)
break; break;
Curl_pgrsTime(data, TIMER_STARTSINGLE); *nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
if(data->set.timeout) if(data->set.timeout)
Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT); Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
@ -2220,7 +2220,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(Curl_pgrsUpdate(data->conn)) if(Curl_pgrsUpdate(data->conn))
result = CURLE_ABORTED_BY_CALLBACK; result = CURLE_ABORTED_BY_CALLBACK;
else else
result = Curl_speedcheck(data, now); result = Curl_speedcheck(data, *nowp);
if(!result) { if(!result) {
send_timeout_ms = 0; send_timeout_ms = 0;
@ -2230,7 +2230,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->progress.ul_limit_size, data->progress.ul_limit_size,
data->set.max_send_speed, data->set.max_send_speed,
data->progress.ul_limit_start, data->progress.ul_limit_start,
now); *nowp);
recv_timeout_ms = 0; recv_timeout_ms = 0;
if(data->set.max_recv_speed > 0) if(data->set.max_recv_speed > 0)
@ -2239,11 +2239,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->progress.dl_limit_size, data->progress.dl_limit_size,
data->set.max_recv_speed, data->set.max_recv_speed,
data->progress.dl_limit_start, data->progress.dl_limit_start,
now); *nowp);
if(!send_timeout_ms && !recv_timeout_ms) { if(!send_timeout_ms && !recv_timeout_ms) {
multistate(data, CURLM_STATE_PERFORM); multistate(data, CURLM_STATE_PERFORM);
Curl_ratelimit(data, now); Curl_ratelimit(data, *nowp);
} }
else if(send_timeout_ms >= recv_timeout_ms) else if(send_timeout_ms >= recv_timeout_ms)
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
@ -2265,7 +2265,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->progress.ul_limit_size, data->progress.ul_limit_size,
data->set.max_send_speed, data->set.max_send_speed,
data->progress.ul_limit_start, data->progress.ul_limit_start,
now); *nowp);
/* check if over recv speed */ /* check if over recv speed */
recv_timeout_ms = 0; recv_timeout_ms = 0;
@ -2274,10 +2274,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->progress.dl_limit_size, data->progress.dl_limit_size,
data->set.max_recv_speed, data->set.max_recv_speed,
data->progress.dl_limit_start, data->progress.dl_limit_start,
now); *nowp);
if(send_timeout_ms || recv_timeout_ms) { if(send_timeout_ms || recv_timeout_ms) {
Curl_ratelimit(data, now); Curl_ratelimit(data, *nowp);
multistate(data, CURLM_STATE_TOOFAST); multistate(data, CURLM_STATE_TOOFAST);
if(send_timeout_ms >= recv_timeout_ms) if(send_timeout_ms >= recv_timeout_ms)
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
@ -2557,7 +2557,7 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
SIGPIPE_VARIABLE(pipe_st); SIGPIPE_VARIABLE(pipe_st);
sigpipe_ignore(data, &pipe_st); sigpipe_ignore(data, &pipe_st);
result = multi_runsingle(multi, now, data); result = multi_runsingle(multi, &now, data);
sigpipe_restore(&pipe_st); sigpipe_restore(&pipe_st);
if(result) if(result)
@ -3031,7 +3031,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
SIGPIPE_VARIABLE(pipe_st); SIGPIPE_VARIABLE(pipe_st);
sigpipe_ignore(data, &pipe_st); sigpipe_ignore(data, &pipe_st);
result = multi_runsingle(multi, now, data); result = multi_runsingle(multi, &now, data);
sigpipe_restore(&pipe_st); sigpipe_restore(&pipe_st);
if(CURLM_OK >= result) { if(CURLM_OK >= result) {

View File

@ -164,9 +164,13 @@ void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
} }
/* /*
*
* Curl_pgrsTime(). Store the current time at the given label. This fetches a
* fresh "now" and returns it.
*
* @unittest: 1399 * @unittest: 1399
*/ */
void Curl_pgrsTime(struct Curl_easy *data, timerid timer) struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer)
{ {
struct curltime now = Curl_now(); struct curltime now = Curl_now();
timediff_t *delta = NULL; timediff_t *delta = NULL;
@ -209,7 +213,7 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
* changing the t_starttransfer time. * changing the t_starttransfer time.
*/ */
if(data->progress.is_t_startransfer_set) { if(data->progress.is_t_startransfer_set) {
return; return now;
} }
else { else {
data->progress.is_t_startransfer_set = true; data->progress.is_t_startransfer_set = true;
@ -228,6 +232,7 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
us = 1; /* make sure at least one microsecond passed */ us = 1; /* make sure at least one microsecond passed */
*delta += us; *delta += us;
} }
return now;
} }
void Curl_pgrsStartNow(struct Curl_easy *data) void Curl_pgrsStartNow(struct Curl_easy *data)

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -49,7 +49,7 @@ void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
void Curl_ratelimit(struct Curl_easy *data, struct curltime now); void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
int Curl_pgrsUpdate(struct connectdata *); int Curl_pgrsUpdate(struct connectdata *);
void Curl_pgrsResetTransferSizes(struct Curl_easy *data); void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
void Curl_pgrsTime(struct Curl_easy *data, timerid timer); struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer);
timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize, timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
curl_off_t startsize, curl_off_t startsize,
curl_off_t limit, curl_off_t limit,