Browse Source

Check negative number from Integer::i() where it is not allowed

Tatsuhiro Tsujikawa 11 years ago
parent
commit
84f1a15e10

+ 2 - 2
src/DefaultBtAnnounce.cc

@@ -317,12 +317,12 @@ DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse,
     minInterval_ = interval_;
   }
   const Integer* comp = downcast<Integer>(dict->get(BtAnnounce::COMPLETE));
-  if(comp) {
+  if(comp && comp->i() >= 0) {
     complete_ = comp->i();
     A2_LOG_DEBUG(fmt("Complete:%d", complete_));
   }
   const Integer* incomp = downcast<Integer>(dict->get(BtAnnounce::INCOMPLETE));
-  if(incomp) {
+  if(incomp && incomp->i() >= 0) {
     incomplete_ = incomp->i();
     A2_LOG_DEBUG(fmt("Incomplete:%d", incomplete_));
   }

+ 3 - 4
src/DefaultExtensionMessageFactory.cc

@@ -119,7 +119,7 @@ DefaultExtensionMessageFactory::createMessage
         throw DL_ABORT_EX("Bad ut_metadata: msg_type not found");
       }
       const Integer* index = downcast<Integer>(dict->get("piece"));
-      if(!index) {
+      if(!index || index->i() < 0) {
         throw DL_ABORT_EX("Bad ut_metadata: piece not found");
       }
       switch(msgType->i()) {
@@ -138,7 +138,7 @@ DefaultExtensionMessageFactory::createMessage
           throw DL_ABORT_EX("Bad ut_metadata data: data not found");
         }
         const Integer* totalSize = downcast<Integer>(dict->get("total_size"));
-        if(!totalSize) {
+        if(!totalSize || totalSize->i() < 0) {
           throw DL_ABORT_EX("Bad ut_metadata data: total_size not found");
         }
         auto m = make_unique<UTMetadataDataExtensionMessage>
@@ -161,8 +161,7 @@ DefaultExtensionMessageFactory::createMessage
       }
       default:
         throw DL_ABORT_EX
-          (fmt("Bad ut_metadata: unknown msg_type=%u",
-               static_cast<unsigned int>(msgType->i())));
+          (fmt("Bad ut_metadata: unknown msg_type=%" PRId64, msgType->i()));
       }
     } else {
       throw DL_ABORT_EX

+ 10 - 0
src/HandshakeExtensionMessage.cc

@@ -188,6 +188,11 @@ HandshakeExtensionMessage::create(const unsigned char* data, size_t length)
     for(auto & elem : *extDict) {
       const Integer* extId = downcast<Integer>(elem.second);
       if(extId) {
+        if(extId->i() < 0 || extId->i() > 255) {
+          A2_LOG_DEBUG(fmt("Extension ID=%" PRId64 " is invalid", extId->i()));
+          continue;
+        }
+
         int key = keyBtExtension(elem.first.c_str());
         if(key == ExtensionMessageRegistry::MAX_EXTENSION) {
           A2_LOG_DEBUG(fmt("Unsupported BitTorrent extension %s=%" PRId64,
@@ -203,6 +208,11 @@ HandshakeExtensionMessage::create(const unsigned char* data, size_t length)
   if(metadataSize) {
     auto size = metadataSize->i();
 
+    if(size < 0) {
+      throw DL_ABORT_EX(fmt("Negative metadataSize %" PRId64 " was received",
+                            size));
+    }
+
     // Only accept metadata smaller than 1MiB.  Be aware that broken
     // clinet can send negative size!
     if(size > 0 && size <= 1024*1024) {

+ 4 - 0
src/RpcMethodImpl.h

@@ -347,6 +347,10 @@ private:
   getPaginationRange
   (int64_t offset, int64_t num, InputIterator first, InputIterator last)
   {
+    if(num <= 0) {
+      return std::make_pair(last, last);
+    }
+
     int64_t size = std::distance(first, last);
     if(offset < 0) {
       int64_t tempoffset = offset+size;

+ 21 - 0
src/bittorrent_helper.cc

@@ -227,6 +227,13 @@ void extractFileEntries
         throw DL_ABORT_EX2(fmt(MSG_MISSING_BT_INFO, C_LENGTH),
                            error_code::BITTORRENT_PARSE_ERROR);
       }
+
+      if(fileLengthData->i() < 0) {
+        throw DL_ABORT_EX2
+          (fmt(MSG_NEGATIVE_LENGTH_BT_INFO, C_LENGTH, fileLengthData->i()),
+           error_code::BITTORRENT_PARSE_ERROR);
+      }
+
       if(length > std::numeric_limits<int64_t>::max() - fileLengthData->i()) {
         throw DOWNLOAD_FAILURE_EXCEPTION(fmt(EX_TOO_LARGE_FILE, length));
       }
@@ -289,6 +296,13 @@ void extractFileEntries
                          error_code::BITTORRENT_PARSE_ERROR);
     }
     int64_t totalLength = lengthData->i();
+
+    if(totalLength < 0) {
+      throw DL_ABORT_EX2
+        (fmt(MSG_NEGATIVE_LENGTH_BT_INFO, C_LENGTH, totalLength),
+         error_code::BITTORRENT_PARSE_ERROR);
+    }
+
     if(totalLength > std::numeric_limits<a2_off_t>::max()) {
       throw DOWNLOAD_FAILURE_EXCEPTION(fmt(EX_TOO_LARGE_FILE, totalLength));
     }
@@ -432,6 +446,13 @@ void processRootDictionary
     throw DL_ABORT_EX2(fmt(MSG_MISSING_BT_INFO, C_PIECE_LENGTH),
                        error_code::BITTORRENT_PARSE_ERROR);
   }
+
+  if(pieceLengthData->i() < 0) {
+    throw DL_ABORT_EX2
+      (fmt(MSG_NEGATIVE_LENGTH_BT_INFO, C_PIECE_LENGTH, pieceLengthData->i()),
+       error_code::BITTORRENT_PARSE_ERROR);
+  }
+
   size_t pieceLength = pieceLengthData->i();
   ctx->setPieceLength(pieceLength);
   // retrieve piece hashes

+ 1 - 0
src/message.h

@@ -149,6 +149,7 @@
 #define MSG_REMOVED_DEFUNCT_CONTROL_FILE _("Removed the defunct control file %s because the download file %s doesn't exist.")
 #define MSG_SHARE_RATIO_REPORT _("Your share ratio was %.1f, uploaded/downloaded=%sB/%sB")
 #define MSG_MISSING_BT_INFO _("Missing %s in torrent metainfo.")
+#define MSG_NEGATIVE_LENGTH_BT_INFO _("%s does not allow negative integer %" PRId64 "")
 #define MSG_NULL_TRACKER_RESPONSE _("Tracker returned null data.")
 #define MSG_WINSOCK_INIT_FAILD _("Windows socket library initialization failed")
 #define MSG_TIME_HAS_PASSED _("%ld second(s) has passed. Stopping application.")