Przeglądaj źródła

Check totalLength of file is less than std::numeric_limits<off_t>::max()

If totalLength is larger than std::numeric_limits<off_t>::max(), throw
DownloadFailureException.
Tatsuhiro Tsujikawa 14 lat temu
rodzic
commit
31163c6785

+ 2 - 3
src/FtpNegotiationCommand.cc

@@ -464,14 +464,13 @@ bool FtpNegotiationCommand::onFileSizeDetermined(off_t totalLength)
 }
 
 bool FtpNegotiationCommand::recvSize() {
-  off_t size = 0;
+  int64_t size = 0;
   int status = ftp_->receiveSizeResponse(size);
   if(status == 0) {
     return false;
   }
   if(status == 213) {
-
-    if(size > INT64_MAX) {
+    if(size > std::numeric_limits<off_t>::max()) {
       throw DL_ABORT_EX2
         (fmt(EX_TOO_LARGE_FILE, static_cast<long long int>(size)),
          error_code::FTP_PROTOCOL_ERROR);

+ 21 - 6
src/HttpHeader.cc

@@ -36,6 +36,7 @@
 #include "Range.h"
 #include "util.h"
 #include "A2STR.h"
+#include "DownloadFailureException.h"
 
 namespace aria2 {
 
@@ -136,11 +137,13 @@ RangeHandle HttpHeader::getRange() const
     if(clenStr.empty()) {
       return SharedHandle<Range>(new Range());
     } else {
-      off_t contentLength = util::parseLLInt(clenStr);
+      int64_t contentLength = util::parseLLInt(clenStr);
       if(contentLength < 0) {
         throw DL_ABORT_EX("Content-Length must be positive");
-      }
-      if(contentLength == 0) {
+      } else if(contentLength > std::numeric_limits<off_t>::max()) {
+        throw DOWNLOAD_FAILURE_EXCEPTION
+          (fmt(EX_TOO_LARGE_FILE, static_cast<long long int>(contentLength)));
+      } else if(contentLength == 0) {
         return SharedHandle<Range>(new Range());
       } else {
         return SharedHandle<Range>
@@ -176,13 +179,25 @@ RangeHandle HttpHeader::getRange() const
   if(minus == slash) {
     return SharedHandle<Range>(new Range());
   }
-  off_t startByte = util::parseLLInt(std::string(byteRangeSpec, minus));
-  off_t endByte = util::parseLLInt(std::string(minus+1, slash));
-  off_t entityLength =
+  int64_t startByte = util::parseLLInt(std::string(byteRangeSpec, minus));
+  int64_t endByte = util::parseLLInt(std::string(minus+1, slash));
+  int64_t entityLength =
     util::parseLLInt(std::string(slash+1, rangeStr.end()));
   if(startByte < 0 || endByte < 0 || entityLength < 0) {
     throw DL_ABORT_EX("byte-range-spec must be positive");
   }
+  if(startByte > std::numeric_limits<off_t>::max()) {
+    throw DOWNLOAD_FAILURE_EXCEPTION
+      (fmt(EX_TOO_LARGE_FILE, static_cast<long long int>(startByte)));
+  }
+  if(endByte > std::numeric_limits<off_t>::max()) {
+    throw DOWNLOAD_FAILURE_EXCEPTION
+      (fmt(EX_TOO_LARGE_FILE, static_cast<long long int>(endByte)));
+  }
+  if(entityLength > std::numeric_limits<off_t>::max()) {
+    throw DOWNLOAD_FAILURE_EXCEPTION
+      (fmt(EX_TOO_LARGE_FILE, static_cast<long long int>(entityLength)));
+  }
   return SharedHandle<Range>(new Range(startByte, endByte, entityLength));
 }
 

+ 3 - 2
src/MetalinkParserStateV3Impl.cc

@@ -148,8 +148,9 @@ void SizeMetalinkParserState::endElement
  const std::string& characters)
 {
   // current metalink specification doesn't require size element.
-  off_t size;
-  if(util::parseLLIntNoThrow(size, characters) && size >= 0) {
+  int64_t size;
+  if(util::parseLLIntNoThrow(size, characters) && size >= 0 &&
+     size <= std::numeric_limits<off_t>::max()) {
     psm->setFileLengthOfEntry(size);
   }
 }

+ 2 - 1
src/MetalinkParserStateV4Impl.cc

@@ -254,7 +254,8 @@ void SizeMetalinkParserStateV4::endElement
  const std::string& characters)
 {
   off_t size;
-  if(util::parseLLIntNoThrow(size, characters) && size >= 0) {
+  if(util::parseLLIntNoThrow(size, characters) && size >= 0 &&
+     size <= std::numeric_limits<off_t>::max()) {
     psm->setFileLengthOfEntry(size);
   } else {
     psm->cancelEntryTransaction();

+ 11 - 4
src/bittorrent_helper.cc

@@ -60,6 +60,7 @@
 #include "FileEntry.h"
 #include "error_code.h"
 #include "array_fun.h"
+#include "DownloadFailureException.h"
 
 namespace aria2 {
 
@@ -232,7 +233,7 @@ void extractFileEntries
   const List* filesList = downcast<List>(infoDict->get(C_FILES));
   if(filesList) {
     fileEntries.reserve(filesList->size());
-    off_t length = 0;
+    int64_t length = 0;
     off_t offset = 0;
     // multi-file mode
     torrent->mode = MULTI;
@@ -248,7 +249,10 @@ void extractFileEntries
                            error_code::BITTORRENT_PARSE_ERROR);
       }
       length += fileLengthData->i();
-
+      if(length > std::numeric_limits<off_t>::max()) {
+        throw DOWNLOAD_FAILURE_EXCEPTION
+          (fmt(EX_TOO_LARGE_FILE, static_cast<long long int>(length)));
+      }
       std::string pathKey;
       if(fileDict->containsKey(C_PATH_UTF8)) {
         pathKey = C_PATH_UTF8;
@@ -304,8 +308,11 @@ void extractFileEntries
       throw DL_ABORT_EX2(fmt(MSG_MISSING_BT_INFO, C_LENGTH.c_str()),
                          error_code::BITTORRENT_PARSE_ERROR);
     }
-    off_t totalLength = lengthData->i();
-
+    int64_t totalLength = lengthData->i();
+    if(totalLength > std::numeric_limits<off_t>::max()) {
+      throw DOWNLOAD_FAILURE_EXCEPTION
+        (fmt(EX_TOO_LARGE_FILE, static_cast<long long int>(totalLength)));
+    }
     // For each uri in urlList, if it ends with '/', then
     // concatenate name to it. Specification just says so.
     std::vector<std::string> uris;