File aria2-0.16.0-CVE-2010-1512.patch of Package aria2

diff -ru aria2c-0.16.0-orig/src/array_fun.h aria2c-0.16.0/src/array_fun.h
--- aria2c-0.16.0-orig/src/array_fun.h	2008-10-06 10:38:51.000000000 +0200
+++ aria2c-0.16.0/src/array_fun.h	2010-05-26 23:20:56.000000000 +0200
@@ -142,6 +142,29 @@
   typedef R result_type;
 };
 
+template<typename T, size_t N>
+class array_wrapper {
+private:
+  T _array[N];
+public:
+  array_wrapper() {}
+
+  operator T*()
+  {
+    return _array;
+  }
+
+  operator const T*() const
+  {
+    return _array;
+  }
+
+  size_t size() const
+  {
+    return N;
+  }
+};
+
 template<typename R, typename A>
 array_fun<R>
 array_negate(A a)
diff -ru aria2c-0.16.0-orig/src/DHTRoutingTableDeserializer.cc aria2c-0.16.0/src/DHTRoutingTableDeserializer.cc
--- aria2c-0.16.0-orig/src/DHTRoutingTableDeserializer.cc	2008-10-06 10:38:50.000000000 +0200
+++ aria2c-0.16.0/src/DHTRoutingTableDeserializer.cc	2010-05-26 23:55:08.000000000 +0200
@@ -41,10 +41,12 @@
 #include "a2netcompat.h"
 #include "StringFormat.h"
 #include "Util.h"
+#include "array_fun.h"
 #include <cerrno>
 #include <cstring>
 #include <istream>
 #include <utility>
+#include <cassert>
 
 namespace aria2 {
 
@@ -57,11 +59,30 @@
   return _localNode;
 }
 
+static void readBytes(unsigned char* buf, size_t buflen,
+		      std::istream& in, size_t readlen)
+{
+  assert(readlen <= buflen);
+  in.read(reinterpret_cast<char*>(buf), readlen);
+}
+
 const std::deque<SharedHandle<DHTNode> >& DHTRoutingTableDeserializer::getNodes() const
 {
   return _nodes;
 }
 
+#define CHECK_STREAM(in, length)				\
+  if(in.gcount() != length) {					\
+  throw DlAbortEx						\
+  (StringFormat("Failed to load DHT routing table. cause:%s",	\
+		"Unexpected EOF").str());			\
+  }								\
+  if(!in) {							\
+  throw DlAbortEx						\
+  (StringFormat("Failed to load DHT routing table. cause:%s",	\
+		strerror(errno)).str());			\
+  }
+
 void DHTRoutingTableDeserializer::deserialize(std::istream& in)
 {
   try {
@@ -91,9 +112,12 @@
     memset(zero, 0, sizeof(zero));
 
     int version;
-    char buf[26];
+    // If you change the code to read more than the size of buf, then
+    // expand the buf size here.
+    array_wrapper<unsigned char, 255> buf;
+
     // header
-    in.read(buf, 8);
+    readBytes(buf, buf.size(), in, 8);
     if(memcmp(header, buf, 8) == 0) {
       version = 3;
     } else if(memcmp(headerCompat, buf, 8) == 0) {
@@ -105,31 +129,46 @@
     }
     // time
     if(version == 2) {
-      in.read(buf, 4);
-      _serializedTime.setTimeInSec(ntohl(*reinterpret_cast<uint32_t*>(buf)));
+      uint32_t temp32;
+      // time
+      in.read(reinterpret_cast<char*>(&temp32), sizeof(temp32));
+      CHECK_STREAM(in, sizeof(temp32));
+      _serializedTime.setTimeInSec(ntohl(temp32));
       // 4bytes reserved
-      in.read(buf, 4);
+      readBytes(buf, buf.size(), in, 4);
+      CHECK_STREAM(in, 4);
+
     } else {
-      in.read(buf, 8);
-      _serializedTime.setTimeInSec(ntoh64(*reinterpret_cast<uint64_t*>(buf)));
+      uint64_t temp64;
+      // time
+      in.read(reinterpret_cast<char*>(&temp64), sizeof(temp64));
+      CHECK_STREAM(in, sizeof(temp64));
+      _serializedTime.setTimeInSec(ntoh64(temp64));
     }
   
     // localnode
     // 8bytes reserved
-    in.read(buf, 8);
+    readBytes(buf, buf.size(), in, 8);
+    CHECK_STREAM(in, 8);
     // localnode ID
-    in.read(buf, DHT_ID_LENGTH);
-    SharedHandle<DHTNode> localNode(new DHTNode(reinterpret_cast<const unsigned char*>(buf)));
+    readBytes(buf, buf.size(), in, DHT_ID_LENGTH);
+    CHECK_STREAM(in, DHT_ID_LENGTH);
+    SharedHandle<DHTNode> localNode(new DHTNode(buf));
     // 4bytes reserved
-    in.read(buf, 4);
+    readBytes(buf, buf.size(), in, 4);
+    CHECK_STREAM(in, 4);
 
     // number of nodes
-    in.read(buf, 4);
-    uint32_t numNodes = ntohl(*reinterpret_cast<uint32_t*>(buf));
+    uint32_t temp32;
+    in.read(reinterpret_cast<char*>(&temp32), sizeof(temp32));
+    CHECK_STREAM(in, sizeof(temp32));
+    uint32_t numNodes = ntohl(temp32);
     // 4bytes reserved
-    in.read(buf, 4);
+    readBytes(buf, buf.size(), in, 4);
+    CHECK_STREAM(in, 4);
 
     // nodes
+    std::deque<SharedHandle<DHTNode> > nodes;
     for(size_t i = 0; i < numNodes; ++i) {
       // Currently, only IPv4 addresses are supported.
       // 1byte compact peer info length
@@ -137,46 +176,59 @@
       in >> peerInfoLen;
       if(peerInfoLen != 6) {
 	// skip this entry
-	in.read(buf, 42+7+6);
+	readBytes(buf, buf.size(), in, 42+7+6);
+	CHECK_STREAM(in, 42+7+6);
 	continue;
       }
       // 7bytes reserved
-      in.read(buf, 7);
+      readBytes(buf, buf.size(), in, 7);
+      CHECK_STREAM(in, 7);
       // 6bytes compact peer info
-      in.read(buf, 6);
+      readBytes(buf, buf.size(), in, 6);
+      CHECK_STREAM(in, 6);
       if(memcmp(zero, buf, 6) == 0) {
 	// skip this entry
-	in.read(buf, 42);
+	readBytes(buf, buf.size(), in, 42);
+	CHECK_STREAM(in, 42);
 	continue;
       }
       std::pair<std::string, uint16_t> peer =
-	PeerMessageUtil::unpackcompact(reinterpret_cast<const unsigned char*>(buf));
+	PeerMessageUtil::unpackcompact(buf);
       if(peer.first.empty()) {
 	// skip this entry
-	in.read(buf, 42);
+	readBytes(buf, buf.size(), in, 42);
+	CHECK_STREAM(in, 42);
 	continue;
       }
       // 2bytes reserved
-      in.read(buf, 2);
+      readBytes(buf, buf.size(), in, 2);
+      CHECK_STREAM(in, 2);
       // 16byte reserved
-      in.read(buf, 16);
+      readBytes(buf, buf.size(), in, 16);
+      CHECK_STREAM(in, 16);
       // localnode ID
-      in.read(buf, DHT_ID_LENGTH);
+      readBytes(buf, buf.size(), in, DHT_ID_LENGTH);
+      CHECK_STREAM(in, DHT_ID_LENGTH);
 
-      SharedHandle<DHTNode> node(new DHTNode(reinterpret_cast<const unsigned char*>(buf)));
+      SharedHandle<DHTNode> node(new DHTNode(buf));
       node->setIPAddress(peer.first);
       node->setPort(peer.second);
       // 4bytes reserved
-      in.read(buf, 4);
+      readBytes(buf, buf.size(), in, 4);
+      CHECK_STREAM(in, 4);
 
-      _nodes.push_back(node);
+      nodes.push_back(node);
     }
     _localNode = localNode;
+    _nodes = nodes;
   } catch(std::ios::failure const& exception) {
     _nodes.clear();
     throw DlAbortEx
       (StringFormat("Failed to load DHT routing table. cause:%s",
 		    strerror(errno)).str());
+  } catch(RecoverableException& e) {
+    _nodes.clear();
+    throw;
   }
 }
 
diff -ru aria2c-0.16.0-orig/src/FilesMetalinkParserState.cc aria2c-0.16.0/src/FilesMetalinkParserState.cc
--- aria2c-0.16.0-orig/src/FilesMetalinkParserState.cc	2008-10-06 10:38:51.000000000 +0200
+++ aria2c-0.16.0/src/FilesMetalinkParserState.cc	2010-05-26 23:20:56.000000000 +0200
@@ -34,6 +34,7 @@
 /* copyright --> */
 #include "FilesMetalinkParserState.h"
 #include "MetalinkParserStateMachine.h"
+#include "Util.h"
 
 namespace aria2 {
 
@@ -50,6 +51,9 @@
     std::map<std::string, std::string>::const_iterator itr =
       attrs.find(FilesMetalinkParserState::NAME);
     if(itr != attrs.end()) {
+      if((*itr).second.empty() || Util::detectDirTraversal((*itr).second)) {
+        return;
+      }
       stm->newEntryTransaction();
       stm->setFileNameOfEntry((*itr).second);
     }
diff -ru aria2c-0.16.0-orig/src/MetalinkParserController.cc aria2c-0.16.0/src/MetalinkParserController.cc
--- aria2c-0.16.0-orig/src/MetalinkParserController.cc	2008-10-06 10:38:51.000000000 +0200
+++ aria2c-0.16.0/src/MetalinkParserController.cc	2010-05-26 23:20:56.000000000 +0200
@@ -46,6 +46,7 @@
 #endif // ENABLE_MESSAGE_DIGEST
 #include "Signature.h"
 #include <algorithm>
+#include "Util.h"
 
 namespace aria2 {
 
@@ -78,9 +79,9 @@
     return;
   }
   if(_tEntry->file.isNull()) {
-    _tEntry->file.reset(new FileEntry(filename, 0, 0));
+    _tEntry->file.reset(new FileEntry(Util::escapePath(filename), 0, 0));
   } else {
-    _tEntry->file->setPath(filename);
+    _tEntry->file->setPath(Util::escapePath(filename));
   }
 }
 
diff -ru aria2c-0.16.0-orig/src/Util.cc aria2c-0.16.0/src/Util.cc
--- aria2c-0.16.0-orig/src/Util.cc	2008-10-06 10:38:51.000000000 +0200
+++ aria2c-0.16.0/src/Util.cc	2010-05-26 23:20:56.000000000 +0200
@@ -901,4 +901,55 @@
   return std::pair<std::string, uint16_t>(host, atoi(service)); // TODO
 }
 
+bool Util::detectDirTraversal(const std::string& s)
+{
+  for(std::string::const_iterator i = s.begin(), eoi = s.end(); i != eoi; ++i) {
+    if(0x00 <= (*i) && (*i) <= 0x1f) {
+      return true;
+    }
+  }
+  return s == A2STR::DOT_C ||
+    s == ".." ||
+    Util::startsWith(s, A2STR::SLASH_C) ||
+    Util::startsWith(s, "./") ||
+    Util::startsWith(s, "../") ||
+    s.find("/../") != std::string::npos ||
+    s.find("/./") != std::string::npos ||
+    Util::endsWith(s, "/") ||
+    Util::endsWith(s, "/.") ||
+    Util::endsWith(s, "/..");
+}
+
+namespace {
+class EscapePath {
+private:
+  char _repChar;
+public:
+  EscapePath(const char& repChar):_repChar(repChar) {}
+
+  char operator()(const char& c) {
+    if(0x00 <= c && c <=0x1f) {
+      return _repChar;
+    }
+#ifdef __MINGW32__
+    // We don't escape '/' because we use it as a path separator.
+    static const char WIN_INVALID_PATH_CHARS[] =
+      { '"', '*', ':', '<', '>', '?', '\\', '|' };
+    if(std::find(vbegin(WIN_INVALID_PATH_CHARS), vend(WIN_INVALID_PATH_CHARS),
+                 c) != vend(WIN_INVALID_PATH_CHARS)) {
+      return _repChar;
+    }
+#endif // __MINGW32__
+    return c;
+  }
+};
+}
+
+std::string Util::escapePath(const std::string& s)
+{
+  std::string d = s;
+  std::transform(d.begin(), d.end(), d.begin(), EscapePath('_'));
+  return d;
+}
+
 } // namespace aria2
diff -ru aria2c-0.16.0-orig/src/Util.h aria2c-0.16.0/src/Util.h
--- aria2c-0.16.0-orig/src/Util.h	2008-10-06 10:38:50.000000000 +0200
+++ aria2c-0.16.0/src/Util.h	2010-05-26 23:20:56.000000000 +0200
@@ -267,6 +267,16 @@
 
   static std::pair<std::string, uint16_t>
   getNumericNameInfo(const struct sockaddr* sockaddr, socklen_t len);
+
+  // Returns true if s contains directory traversal path component such
+  // as '..' or it contains null or control character which may fool
+  // user.
+  static bool detectDirTraversal(const std::string& s);
+
+  // Replaces null(0x00) and control character(0x01-0x1f) with '_'. If
+  // __MINGW32__ is defined, following characters are also replaced with
+  // '_': '"', '*', ':', '<', '>', '?', '\', '|'.
+  static std::string escapePath(const std::string& s);
 };
 
 } // namespace aria2
openSUSE Build Service is sponsored by