curl: detect and bail out early on parameter integer overflows

Make the number parser aware of the maximum limit curl accepts for a
value and return an error immediately if larger, instead of running an
integer overflow later.

Fixes #1730
This commit is contained in:
Daniel Stenberg 2017-08-06 20:10:40 +02:00
parent d6c8def82a
commit f1c26efcbf
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
5 changed files with 36 additions and 14 deletions

View file

@ -545,7 +545,8 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
GetStr(&config->oauth_bearer, nextarg); GetStr(&config->oauth_bearer, nextarg);
break; break;
case 'c': /* connect-timeout */ case 'c': /* connect-timeout */
err = str2udouble(&config->connecttimeout, nextarg); err = str2udouble(&config->connecttimeout, nextarg,
LONG_MAX/1000);
if(err) if(err)
return err; return err;
break; break;
@ -1047,7 +1048,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
return err; return err;
break; break;
case 'R': /* --expect100-timeout */ case 'R': /* --expect100-timeout */
err = str2udouble(&config->expect100timeout, nextarg); err = str2udouble(&config->expect100timeout, nextarg, LONG_MAX/1000);
if(err) if(err)
return err; return err;
break; break;
@ -1713,7 +1714,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break; break;
case 'm': case 'm':
/* specified max time */ /* specified max time */
err = str2udouble(&config->timeout, nextarg); err = str2udouble(&config->timeout, nextarg, LONG_MAX/1000);
if(err) if(err)
return err; return err;
break; break;

View file

@ -41,6 +41,7 @@ typedef enum {
PARAM_NO_MEM, PARAM_NO_MEM,
PARAM_NEXT_OPERATION, PARAM_NEXT_OPERATION,
PARAM_NO_PREFIX, PARAM_NO_PREFIX,
PARAM_NUMBER_TOO_LARGE,
PARAM_LAST PARAM_LAST
} ParameterError; } ParameterError;

View file

@ -64,6 +64,8 @@ const char *param2text(int res)
return "out of memory"; return "out of memory";
case PARAM_NO_PREFIX: case PARAM_NO_PREFIX:
return "the given option can't be reversed with a --no- prefix"; return "the given option can't be reversed with a --no- prefix";
case PARAM_NUMBER_TOO_LARGE:
return "too large number";
default: default:
return "unknown error"; return "unknown error";
} }

View file

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2017, 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
@ -164,7 +164,11 @@ ParameterError str2num(long *val, const char *str)
{ {
if(str) { if(str) {
char *endptr; char *endptr;
long num = strtol(str, &endptr, 10); long num;
errno = 0;
num = strtol(str, &endptr, 10);
if(errno == ERANGE)
return PARAM_NUMBER_TOO_LARGE;
if((endptr != str) && (endptr == str + strlen(str))) { if((endptr != str) && (endptr == str + strlen(str))) {
*val = num; *val = num;
return PARAM_OK; /* Ok */ return PARAM_OK; /* Ok */
@ -197,16 +201,27 @@ ParameterError str2unum(long *val, const char *str)
* Parse the string and write the double in the given address. Return PARAM_OK * Parse the string and write the double in the given address. Return PARAM_OK
* on success, otherwise a parameter specific error enum. * on success, otherwise a parameter specific error enum.
* *
* The 'max' argument is the maximum value allowed, as the numbers are often
* multiplied when later used.
*
* Since this function gets called with the 'nextarg' pointer from within the * Since this function gets called with the 'nextarg' pointer from within the
* getparameter a lot, we must check it for NULL before accessing the str * getparameter a lot, we must check it for NULL before accessing the str
* data. * data.
*/ */
ParameterError str2double(double *val, const char *str) static ParameterError str2double(double *val, const char *str, long max)
{ {
if(str) { if(str) {
char *endptr; char *endptr;
double num = strtod(str, &endptr); double num;
errno = 0;
num = strtod(str, &endptr);
if(errno == ERANGE)
return PARAM_NUMBER_TOO_LARGE;
if((long)val > max) {
/* too large */
return PARAM_NUMBER_TOO_LARGE;
}
if((endptr != str) && (endptr == str + strlen(str))) { if((endptr != str) && (endptr == str + strlen(str))) {
*val = num; *val = num;
return PARAM_OK; /* Ok */ return PARAM_OK; /* Ok */
@ -219,14 +234,17 @@ ParameterError str2double(double *val, const char *str)
* Parse the string and write the double in the given address. Return PARAM_OK * Parse the string and write the double in the given address. Return PARAM_OK
* on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS! * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
* *
* The 'max' argument is the maximum value allowed, as the numbers are often
* multiplied when later used.
*
* Since this function gets called with the 'nextarg' pointer from within the * Since this function gets called with the 'nextarg' pointer from within the
* getparameter a lot, we must check it for NULL before accessing the str * getparameter a lot, we must check it for NULL before accessing the str
* data. * data.
*/ */
ParameterError str2udouble(double *val, const char *str) ParameterError str2udouble(double *val, const char *str, long max)
{ {
ParameterError result = str2double(val, str); ParameterError result = str2double(val, str, max);
if(result != PARAM_OK) if(result != PARAM_OK)
return result; return result;
if(*val < 0) if(*val < 0)
@ -384,11 +402,12 @@ ParameterError str2offset(curl_off_t *val, const char *str)
#if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) #if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
*val = curlx_strtoofft(str, &endptr, 0); *val = curlx_strtoofft(str, &endptr, 0);
if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (errno == ERANGE)) if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (errno == ERANGE))
return PARAM_BAD_NUMERIC; return PARAM_NUMBER_TOO_LARGE;
#else #else
errno = 0;
*val = strtol(str, &endptr, 0); *val = strtol(str, &endptr, 0);
if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE) if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
return PARAM_BAD_NUMERIC; return PARAM_NUMBER_TOO_LARGE;
#endif #endif
if((endptr != str) && (endptr == str + strlen(str))) if((endptr != str) && (endptr == str + strlen(str)))
return PARAM_OK; return PARAM_OK;

View file

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2017, 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
@ -33,8 +33,7 @@ void cleanarg(char *str);
ParameterError str2num(long *val, const char *str); ParameterError str2num(long *val, const char *str);
ParameterError str2unum(long *val, const char *str); ParameterError str2unum(long *val, const char *str);
ParameterError str2double(double *val, const char *str); ParameterError str2udouble(double *val, const char *str, long max);
ParameterError str2udouble(double *val, const char *str);
long proto2num(struct OperationConfig *config, long *val, const char *str); long proto2num(struct OperationConfig *config, long *val, const char *str);