Unverified Commit ff50fe03 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

strtoofft: reduce integer overflow risks globally

... make sure we bail out on overflows.

Reported-by: Brian Carpenter
Closes #1758
parent b53b4e44
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -593,15 +593,21 @@ Curl_cookie_add(struct Curl_easy *data,
    } while(semiptr);

    if(co->maxage) {
      co->expires =
        curlx_strtoofft((*co->maxage=='\"')?
                        &co->maxage[1]:&co->maxage[0], NULL, 10);
      CURLofft offt;
      offt = curlx_strtoofft((*co->maxage=='\"')?
                             &co->maxage[1]:&co->maxage[0], NULL, 10,
                             &co->expires);
      if(offt == CURL_OFFT_FLOW)
        /* overflow, used max value */
        co->expires = CURL_OFF_T_MAX;
      else if(!offt) {
        if(CURL_OFF_T_MAX - now < co->expires)
        /* avoid overflow */
          /* would overflow */
          co->expires = CURL_OFF_T_MAX;
        else
          co->expires += now;
      }
    }
    else if(co->expirestr) {
      /* Note that if the date couldn't get parsed for whatever reason,
         the cookie will be treated as a session cookie */
@@ -753,7 +759,8 @@ Curl_cookie_add(struct Curl_easy *data,
        co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
        break;
      case 4:
        co->expires = curlx_strtoofft(ptr, NULL, 10);
        if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
          badcookie = TRUE;
        break;
      case 5:
        co->name = strdup(ptr);
+13 −11
Original line number Diff line number Diff line
@@ -139,26 +139,28 @@ static CURLcode file_range(struct connectdata *conn)
  struct Curl_easy *data = conn->data;

  if(data->state.use_range && data->state.range) {
    from=curlx_strtoofft(data->state.range, &ptr, 0);
    CURLofft from_t;
    CURLofft to_t;
    from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
    if(from_t == CURL_OFFT_FLOW)
      return CURLE_RANGE_ERROR;
    while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
      ptr++;
    to=curlx_strtoofft(ptr, &ptr2, 0);
    if(ptr == ptr2) {
      /* we didn't get any digit */
      to=-1;
    }
    if((-1 == to) && (from>=0)) {
    to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
    if(to_t == CURL_OFFT_FLOW)
      return CURLE_RANGE_ERROR;
    if((to_t == CURL_OFFT_INVAL) && !from_t) {
      /* X - */
      data->state.resume_from = from;
      DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
                   from));
    }
    else if(from < 0) {
    else if((from_t == CURL_OFFT_INVAL) && !to_t) {
      /* -Y */
      data->req.maxdownload = -from;
      data->state.resume_from = from;
      data->req.maxdownload = to;
      data->state.resume_from = -to;
      DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
                   -from));
                   to));
    }
    else {
      /* X-Y */
+18 −15
Original line number Diff line number Diff line
@@ -2260,11 +2260,13 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
{
  CURLcode result = CURLE_OK;
  struct Curl_easy *data=conn->data;
  curl_off_t filesize;
  curl_off_t filesize = -1;
  char *buf = data->state.buffer;

  /* get the size from the ascii string: */
  filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
  if(ftpcode == 213)
    /* ignores parsing errors, which will make the size remain unknown */
    (void)curlx_strtoofft(buf+4, NULL, 0, &filesize);

  if(instate == FTP_SIZE) {
#ifdef CURL_FTP_HTTPSTYLE_HEAD
@@ -2435,7 +2437,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
        /* if we have nothing but digits: */
        if(bytes++) {
          /* get the number! */
          size = curlx_strtoofft(bytes, NULL, 0);
          (void)curlx_strtoofft(bytes, NULL, 0, &size);
        }
      }
    }
@@ -3466,31 +3468,32 @@ static CURLcode ftp_range(struct connectdata *conn)
{
  curl_off_t from, to;
  char *ptr;
  char *ptr2;
  struct Curl_easy *data = conn->data;
  struct ftp_conn *ftpc = &conn->proto.ftpc;

  if(data->state.use_range && data->state.range) {
    from=curlx_strtoofft(data->state.range, &ptr, 0);
    CURLofft from_t;
    CURLofft to_t;
    from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
    if(from_t == CURL_OFFT_FLOW)
      return CURLE_RANGE_ERROR;
    while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
      ptr++;
    to=curlx_strtoofft(ptr, &ptr2, 0);
    if(ptr == ptr2) {
      /* we didn't get any digit */
      to=-1;
    }
    if((-1 == to) && (from>=0)) {
    to_t = curlx_strtoofft(ptr, NULL, 0, &to);
    if(to_t == CURL_OFFT_FLOW)
      return CURLE_RANGE_ERROR;
    if((to_t == CURL_OFFT_INVAL) && !from_t) {
      /* X - */
      data->state.resume_from = from;
      DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
                   " to end of file\n", from));
    }
    else if(from < 0) {
    else if(!to_t && (from_t == CURL_OFFT_INVAL)) {
      /* -Y */
      data->req.maxdownload = -from;
      data->state.resume_from = from;
      data->req.maxdownload = to;
      data->state.resume_from = -to;
      DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
                   " bytes\n", -from));
                   " bytes\n", to));
    }
    else {
      /* X-Y */
+14 −22
Original line number Diff line number Diff line
@@ -609,7 +609,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
            char *p;
            curl_off_t fsize;
            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
            fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
            if(!curlx_strtoofft(finfo->b_data+parser->item_offset,
                                &p, 10, &fsize)) {
              if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
                 fsize != CURL_OFF_T_MIN) {
                parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
@@ -620,6 +621,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
              parser->state.UNIX.main = PL_UNIX_TIME;
              parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
            }
          }
          else if(!ISDIGIT(c)) {
            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
            return bufflen;
@@ -935,19 +937,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
            }
            else {
              char *endptr;
              finfo->size = curlx_strtoofft(finfo->b_data +
              if(curlx_strtoofft(finfo->b_data +
                                 parser->item_offset,
                                            &endptr, 10);
              if(!*endptr) {
                if(finfo->size == CURL_OFF_T_MAX ||
                   finfo->size == CURL_OFF_T_MIN) {
                  if(errno == ERANGE) {
                    PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
                    return bufflen;
                  }
                }
              }
              else {
                                 &endptr, 10, &finfo->size)) {
                PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
                return bufflen;
              }
+30 −26
Original line number Diff line number Diff line
@@ -3486,7 +3486,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
    /* Check for Content-Length: header lines to get size */
    if(!k->ignorecl && !data->set.ignorecl &&
       checkprefix("Content-Length:", k->p)) {
      curl_off_t contentlength = curlx_strtoofft(k->p+15, NULL, 10);
      curl_off_t contentlength;
      if(!curlx_strtoofft(k->p+15, NULL, 10, &contentlength)) {
        if(data->set.max_filesize &&
           contentlength > data->set.max_filesize) {
          failf(data, "Maximum file size exceeded");
@@ -3509,6 +3510,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                ", closing after transfer\n", contentlength);
        }
      }
      else
        infof(data, "Illegal Content-Length: header\n");
    }
    /* check for Content-Type: header lines to get the MIME-type */
    else if(checkprefix("Content-Type:", k->p)) {
      char *contenttype = Curl_copy_header_value(k->p);
@@ -3682,12 +3686,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,

      /* if it truly stopped on a digit */
      if(ISDIGIT(*ptr)) {
        k->offset = curlx_strtoofft(ptr, NULL, 10);

        if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
          if(data->state.resume_from == k->offset)
            /* we asked for a resume and we got it */
            k->content_range = TRUE;
        }
      }
      else
        data->state.resume_from = 0; /* get everything */
    }
Loading