diff -u poco-1.3.6p1/debian/control poco-1.3.6p1/debian/control --- poco-1.3.6p1/debian/control +++ poco-1.3.6p1/debian/control @@ -1,7 +1,7 @@ Source: poco Priority: optional Maintainer: Cristian Greco -Uploaders: Patrick Gansterer +Uploaders: Patrick Gansterer , Maxime Chatelle Build-Depends: debhelper (>= 5), dpatch, libexpat1-dev, libmysqlclient-dev, libpcre3-dev (>= 7.8), libsqlite3-dev (>= 3.6.13), libssl-dev (>= 0.9.8), unixodbc-dev, zlib1g-dev Standards-Version: 3.8.3 Section: libs diff -u poco-1.3.6p1/debian/changelog poco-1.3.6p1/debian/changelog --- poco-1.3.6p1/debian/changelog +++ poco-1.3.6p1/debian/changelog @@ -1,3 +1,21 @@ +poco (1.3.6p1-4+deb7u1build1) trusty-security; urgency=medium + + * fake sync from Debian + + -- Steve Beattie Wed, 14 Feb 2018 14:40:55 -0800 + +poco (1.3.6p1-4+deb7u1) wheezy-security; urgency=high + + [Maxime Chatelle] + * Adds debian/patches/70_fix_CVE-2014-0350.dpatch (Closes: #746637). + The patch is backported from poco-1.4.7 where the vulnerability + has been fixed. + + [Jochen Sprickerhof] + * Add backported patch for CVE-2017-1000472 + + -- Jochen Sprickerhof Wed, 10 Jan 2018 13:11:20 +0100 + poco (1.3.6p1-4) unstable; urgency=low * Wheezy cleanup release (3): should fix FTBFS on GNU/kFreeBSD for real. diff -u poco-1.3.6p1/debian/patches/00list poco-1.3.6p1/debian/patches/00list --- poco-1.3.6p1/debian/patches/00list +++ poco-1.3.6p1/debian/patches/00list @@ -6,0 +7,2 @@ +70_fix_CVE-2014-0350.dpatch +80_zip_vulnerability.dpatch only in patch2: unchanged: --- poco-1.3.6p1.orig/debian/patches/70_fix_CVE-2014-0350.dpatch +++ poco-1.3.6p1/debian/patches/70_fix_CVE-2014-0350.dpatch @@ -0,0 +1,115 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 70_fix_CVE-2014-0350.dpatch by Maxime Chatelle +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Backported fix against CVE-2014-0350 + +@DPATCH@ + +--- poco-1.3.6p1-4/NetSSL_OpenSSL/src/X509Certificate.cpp 2009-12-21 19:15:02.000000000 +0100 ++++ poco-1.3.6p1-5/NetSSL_OpenSSL/src/X509Certificate.cpp 2014-11-18 11:41:26.033979022 +0100 +@@ -48,6 +48,21 @@ + #include + #include + ++static bool matchWildcard(const std::string& wildcard, const std::string& hostName) ++{ ++ // fix wildcards ++ std::string wildcardExpr("^"); ++ wildcardExpr += Poco::replace(wildcard, ".", "\\."); ++ Poco::replaceInPlace(wildcardExpr, "*", ".*"); ++ Poco::replaceInPlace(wildcardExpr, "..*", ".*"); ++ Poco::replaceInPlace(wildcardExpr, "?", ".?"); ++ Poco::replaceInPlace(wildcardExpr, "..?", ".?"); ++ wildcardExpr += "$"; ++ ++ Poco::RegularExpression expr(wildcardExpr, Poco::RegularExpression::RE_CASELESS); ++ return expr.match(hostName); ++} ++ + + namespace Poco { + namespace Net { +@@ -107,51 +122,47 @@ + std::string commonName; + std::set dnsNames; + certificate.extractNames(commonName, dnsNames); ++ if (!commonName.empty()) dnsNames.insert(commonName); + bool ok = (dnsNames.find(hostName) != dnsNames.end()); +- +- char buffer[NAME_BUFFER_SIZE]; +- X509_NAME* subj = 0; +- if (!ok && (subj = X509_get_subject_name(const_cast(certificate.certificate()))) && X509_NAME_get_text_by_NID(subj, NID_commonName, buffer, sizeof(buffer)) > 0) ++ if (!ok) + { +- buffer[NAME_BUFFER_SIZE - 1] = 0; +- std::string commonName(buffer); // commonName can contain wildcards like *.appinf.com +- try ++ for (std::set::const_iterator it = dnsNames.begin(); !ok && it != dnsNames.end(); ++it) + { +- // two cases: strData contains wildcards or not +- if (containsWildcards(commonName)) ++ try + { +- // a compare by IPAddress is not possible with wildcards +- // only allow compare by name +- const HostEntry& heData = DNS::resolve(hostName); +- ok = matchByAlias(commonName, heData); +- } +- else +- { +- // it depends on hostName if we compare by IP or by alias +- IPAddress ip; +- if (IPAddress::tryParse(hostName, ip)) ++ // two cases: strData contains wildcards or not ++ if (containsWildcards(*it)) + { +- // compare by IP +- const HostEntry& heData = DNS::resolve(commonName); +- const HostEntry::AddressList& addr = heData.addresses(); +- HostEntry::AddressList::const_iterator it = addr.begin(); +- HostEntry::AddressList::const_iterator itEnd = addr.end(); +- for (; it != itEnd && !ok; ++it) +- { +- ok = (*it == ip); +- } ++ // a compare by IPAddress is not possible with wildcards ++ // only allow compare by name ++ ok = matchWildcard(*it, hostName); + } + else + { +- // compare by name +- const HostEntry& heData = DNS::resolve(hostName); +- ok = matchByAlias(commonName, heData); ++ // it depends on hostName if we compare by IP or by alias ++ IPAddress ip; ++ if (IPAddress::tryParse(hostName, ip)) ++ { ++ // compare by IP ++ const HostEntry& heData = DNS::resolve(*it); ++ const HostEntry::AddressList& addr = heData.addresses(); ++ HostEntry::AddressList::const_iterator it = addr.begin(); ++ HostEntry::AddressList::const_iterator itEnd = addr.end(); ++ for (; it != itEnd && !ok; ++it) ++ { ++ ok = (*it == ip); ++ } ++ } ++ else ++ { ++ ok = Poco::icompare(*it, hostName) == 0; ++ } + } + } +- } +- catch (HostNotFoundException&) +- { +- return X509_V_ERR_APPLICATION_VERIFICATION; ++ catch (HostNotFoundException&) ++ { ++ return X509_V_ERR_APPLICATION_VERIFICATION; ++ } + } + } + only in patch2: unchanged: --- poco-1.3.6p1.orig/debian/patches/80_zip_vulnerability.dpatch +++ poco-1.3.6p1/debian/patches/80_zip_vulnerability.dpatch @@ -0,0 +1,360 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 80_zip_vulnerability.dpatch by Guenter Obiltschnig +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: merge zip entry absolute path vulnerability fix (#1968) from develop + +@DPATCH@ +diff --git a/Zip/include/Poco/Zip/ZipCommon.h b/Zip/include/Poco/Zip/ZipCommon.h +index 5aeccc4..f030a0e 100644 +--- a/Zip/include/Poco/Zip/ZipCommon.h ++++ b/Zip/include/Poco/Zip/ZipCommon.h +@@ -110,6 +110,10 @@ public: + }; + + static const std::string ILLEGAL_PATH; ++ ++ static bool isValidPath(const std::string& path); ++ /// Checks whether the given path is valid (does ++ /// not contain ".." path segments). + }; + + +diff --git a/Zip/src/Compress.cpp b/Zip/src/Compress.cpp +index afc972b..86f8575 100644 +--- a/Zip/src/Compress.cpp ++++ b/Zip/src/Compress.cpp +@@ -200,8 +200,8 @@ void Compress::addDirectory(const Poco::Path& entryName, const Poco::DateTime& l + throw ZipException("Illegal entry name /"); + if (fileStr.empty()) + throw ZipException("Illegal empty entry name"); +- if (fileStr.find(ZipCommon::ILLEGAL_PATH) != std::string::npos) +- throw ZipException("Illegal entry name " + fileStr + " containing " + ZipCommon::ILLEGAL_PATH); ++ if (!ZipCommon::isValidPath(fileStr)) ++ throw ZipException("Illegal entry name " + fileStr + " containing parent directory reference"); + + if (entryName.depth() > 1) + { +diff --git a/Zip/src/Decompress.cpp b/Zip/src/Decompress.cpp +index b711fb0..903c198 100644 +--- a/Zip/src/Decompress.cpp ++++ b/Zip/src/Decompress.cpp +@@ -94,8 +94,8 @@ bool Decompress::handleZipEntry(std::istream& zipStream, const ZipLocalFileHeade + if (!_flattenDirs) + { + std::string dirName = hdr.getFileName(); +- if (dirName.find(ZipCommon::ILLEGAL_PATH) != std::string::npos) +- throw ZipException("Illegal entry name " + dirName + " containing " + ZipCommon::ILLEGAL_PATH); ++ if (!ZipCommon::isValidPath(dirName)) ++ throw ZipException("Illegal entry name", dirName); + Poco::Path dir(_outDir, dirName); + dir.makeDirectory(); + Poco::File aFile(dir); +@@ -114,8 +114,8 @@ bool Decompress::handleZipEntry(std::istream& zipStream, const ZipLocalFileHeade + fileName = p.getFileName(); + } + +- if (fileName.find(ZipCommon::ILLEGAL_PATH) != std::string::npos) +- throw ZipException("Illegal entry name " + fileName + " containing " + ZipCommon::ILLEGAL_PATH); ++ if (!ZipCommon::isValidPath(fileName)) ++ throw ZipException("Illegal entry name", fileName); + + Poco::Path file(fileName); + file.makeFile(); +diff --git a/Zip/src/ZipCommon.cpp b/Zip/src/ZipCommon.cpp +index 7771726..10d5902 100644 +--- a/Zip/src/ZipCommon.cpp ++++ b/Zip/src/ZipCommon.cpp +@@ -35,6 +35,7 @@ + + + #include "Poco/Zip/ZipCommon.h" ++#include "Poco/Path.h" + + + namespace Poco { +@@ -43,5 +44,37 @@ namespace Zip { + + const std::string ZipCommon::ILLEGAL_PATH(".."); + ++bool ZipCommon::isValidPath(const std::string& path) ++{ ++ try ++ { ++ if (Path(path, Path::PATH_UNIX).isAbsolute() || Path(path, Path::PATH_WINDOWS).isAbsolute()) ++ return false; ++ } ++ catch (...) ++ { ++ return false; ++ } ++ ++ if (path == "..") ++ return false; ++ if ((path.size() >= 3) && path.compare(0, 3, "../") == 0) ++ return false; ++ if ((path.size() >= 3) && path.compare(0, 3, "..\\") == 0) ++ return false; ++ if (path.find("/../") != std::string::npos) ++ return false; ++ if (path.find("\\..\\") != std::string::npos) ++ return false; ++ if (path.find("/..\\") != std::string::npos) ++ return false; ++ if (path.find("\\../") != std::string::npos) ++ return false; ++ if ((path.size() >= 2) && path.compare(0, 2, "~/") == 0) ++ return false; ++ ++ return true; ++} ++ + + } } // namespace Poco::Zip +diff --git a/Zip/src/ZipUtil.cpp b/Zip/src/ZipUtil.cpp +index 7199ebb..9657ef2 100644 +--- a/Zip/src/ZipUtil.cpp ++++ b/Zip/src/ZipUtil.cpp +@@ -196,8 +196,8 @@ void ZipUtil::verifyZipEntryFileName(const std::string& fn) + throw ZipException("Illegal entry name /"); + if (fn.empty()) + throw ZipException("Illegal empty entry name"); +- if (fn.find(ZipCommon::ILLEGAL_PATH) != std::string::npos) +- throw ZipException("Illegal entry name " + fn + " containing " + ZipCommon::ILLEGAL_PATH); ++ if (!ZipCommon::isValidPath(fn)) ++ throw ZipException("Illegal entry name " + fn + " containing parent directory reference"); + } + + +diff --git a/Zip/testsuite/src/CompressTest.cpp b/Zip/testsuite/src/CompressTest.cpp +index 4418fcd..467be64 100644 +--- a/Zip/testsuite/src/CompressTest.cpp ++++ b/Zip/testsuite/src/CompressTest.cpp +@@ -56,7 +56,7 @@ CompressTest::~CompressTest() + + void CompressTest::testSingleFile() + { +- std::ofstream out("appinf.zip", std::ios::binary); ++ std::ofstream out((Poco::Path::temp() + "appinf.zip").c_str(), std::ios::binary); + Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Compress c(out, true); + c.addFile(theFile, theFile.getFileName()); +@@ -66,10 +66,9 @@ void CompressTest::testSingleFile() + + void CompressTest::testDirectory() + { +- std::ofstream out("pocobin.zip", std::ios::binary); ++ std::ofstream out((Poco::Path::temp() + "pocobin.zip").c_str(), std::ios::binary); + Poco::File aFile("some/"); +- if (aFile.exists()) +- aFile.remove(true); ++ if (aFile.exists()) aFile.remove(true); + Poco::File aDir("some/recursive/dir/"); + aDir.createDirectories(); + Poco::File aDir2("some/other/recursive/dir/"); +@@ -85,19 +84,20 @@ void CompressTest::testDirectory() + Compress c(out, true); + c.addRecursive(theFile, ZipCommon::CL_MAXIMUM, false, theFile); + ZipArchive a(c.close()); ++ Poco::File(aFile).remove(true); + } + + + void CompressTest::testManipulator() + { + { +- std::ofstream out("appinf.zip", std::ios::binary); ++ std::ofstream out((Poco::Path::temp() + "appinf.zip").c_str(), std::ios::binary); + Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Compress c(out, true); + c.addFile(theFile, theFile.getFileName()); + ZipArchive a(c.close()); + } +- ZipManipulator zm("appinf.zip", true); ++ ZipManipulator zm(Poco::Path::temp() + "appinf.zip", true); + zm.renameFile("test.zip", "renamedtest.zip"); + zm.addFile("doc/othertest.zip", ZipTest::getTestFile("test.zip")); + ZipArchive archive=zm.commit(); +@@ -108,13 +108,13 @@ void CompressTest::testManipulator() + void CompressTest::testManipulatorDel() + { + { +- std::ofstream out("appinf.zip", std::ios::binary); ++ std::ofstream out((Poco::Path::temp() + "appinf.zip").c_str(), std::ios::binary); + Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Compress c(out, true); + c.addFile(theFile, theFile.getFileName()); + ZipArchive a(c.close()); + } +- ZipManipulator zm("appinf.zip", true); ++ ZipManipulator zm(Poco::Path::temp() + "appinf.zip", true); + zm.deleteFile("test.zip"); + zm.addFile("doc/data.zip", ZipTest::getTestFile("data.zip")); + ZipArchive archive=zm.commit(); +@@ -126,13 +126,13 @@ void CompressTest::testManipulatorDel() + void CompressTest::testManipulatorReplace() + { + { +- std::ofstream out("appinf.zip", std::ios::binary); ++ std::ofstream out((Poco::Path::temp() + "appinf.zip").c_str(), std::ios::binary); + Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Compress c(out, true); + c.addFile(theFile, theFile.getFileName()); + ZipArchive a(c.close()); + } +- ZipManipulator zm("appinf.zip", true); ++ ZipManipulator zm(Poco::Path::temp() + "appinf.zip", true); + zm.replaceFile("test.zip", ZipTest::getTestFile("doc.zip")); + + ZipArchive archive=zm.commit(); +@@ -144,7 +144,7 @@ void CompressTest::testManipulatorReplace() + void CompressTest::testSetZipComment() + { + std::string comment("Testing...123..."); +- std::ofstream out("comment.zip", std::ios::binary); ++ std::ofstream out((Poco::Path::temp() + "comment.zip").c_str(), std::ios::binary); + Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Compress c(out, true); + c.addFile(theFile, theFile.getFileName()); +diff --git a/Zip/testsuite/src/ZipTest.cpp b/Zip/testsuite/src/ZipTest.cpp +index fd35be5..66fe103 100644 +--- a/Zip/testsuite/src/ZipTest.cpp ++++ b/Zip/testsuite/src/ZipTest.cpp +@@ -104,7 +104,7 @@ void ZipTest::testCrcAndSizeAfterData() + std::string testFile = getTestFile("data.zip"); + std::ifstream inp(testFile.c_str(), std::ios::binary); + assert (inp.good()); +- Decompress dec(inp, Poco::Path()); ++ Decompress dec(inp, Poco::Path::temp()); + dec.EError += Poco::Delegate >(this, &ZipTest::onDecompressError); + dec.decompressAllFiles(); + dec.EError -= Poco::Delegate >(this, &ZipTest::onDecompressError); +@@ -128,7 +128,7 @@ void ZipTest::testCrcAndSizeAfterDataWithArchive() + Poco::Path path(it->second.getFileName()); + if (path.isFile()) + { +- std::ofstream os("test.dat"); ++ std::ofstream os((Poco::Path::temp() + "test.dat").c_str()); + Poco::StreamCopier::copyStream(zipis,os); + } + } +@@ -161,7 +161,7 @@ void ZipTest::testDecompress() + std::string testFile = getTestFile("test.zip"); + std::ifstream inp(testFile.c_str(), std::ios::binary); + assert (inp.good()); +- Decompress dec(inp, Poco::Path()); ++ Decompress dec(inp, Poco::Path::temp()); + dec.EError += Poco::Delegate >(this, &ZipTest::onDecompressError); + dec.decompressAllFiles(); + dec.EError -= Poco::Delegate >(this, &ZipTest::onDecompressError); +@@ -175,7 +175,7 @@ void ZipTest::testDecompressFlat() + std::string testFile = getTestFile("test.zip"); + std::ifstream inp(testFile.c_str(), std::ios::binary); + assert (inp.good()); +- Decompress dec(inp, Poco::Path(), true); ++ Decompress dec(inp, Poco::Path::temp(), true); + dec.EError += Poco::Delegate >(this, &ZipTest::onDecompressError); + dec.decompressAllFiles(); + dec.EError -= Poco::Delegate >(this, &ZipTest::onDecompressError); +@@ -184,6 +184,71 @@ void ZipTest::testDecompressFlat() + } + + ++void ZipTest::testDecompressVuln() ++{ ++ std::string testFile = getTestFile("vuln.zip"); ++ std::ifstream inp(testFile.c_str(), std::ios::binary); ++ assert(inp.good()); ++ Decompress dec(inp, Poco::Path::temp()); ++ dec.EError += Poco::Delegate >(this, &ZipTest::onDecompressError); ++ dec.decompressAllFiles(); ++ dec.EError -= Poco::Delegate >(this, &ZipTest::onDecompressError); ++ assert (_errCnt == 1); ++ assert (dec.mapping().empty()); ++} ++ ++ ++void ZipTest::testDecompressFlatVuln() ++{ ++ std::string testFile = getTestFile("vuln.zip"); ++ std::ifstream inp(testFile.c_str(), std::ios::binary); ++ assert(inp.good()); ++ Decompress dec(inp, Poco::Path::temp(), true); ++ dec.EError += Poco::Delegate >(this, &ZipTest::onDecompressError); ++ dec.decompressAllFiles(); ++ dec.EError -= Poco::Delegate >(this, &ZipTest::onDecompressError); ++ assert (_errCnt == 0); ++ assert (!dec.mapping().empty()); ++} ++ ++ ++void ZipTest::testValidPath() ++{ ++ assert (ZipCommon::isValidPath(".")); ++ assert (ZipCommon::isValidPath("file.txt")); ++ assert (ZipCommon::isValidPath(".file.txt")); ++ assert (ZipCommon::isValidPath("..file.txt")); ++ assert (ZipCommon::isValidPath("file.txt..")); ++ assert (ZipCommon::isValidPath(".file..txt")); ++ assert (ZipCommon::isValidPath("~file..txt")); ++ assert (ZipCommon::isValidPath("~file/~")); ++ assert (ZipCommon::isValidPath("dir/~")); ++ assert (ZipCommon::isValidPath("some")); ++ assert (ZipCommon::isValidPath("some/dir")); ++ assert (ZipCommon::isValidPath("some/dir/or/another")); ++ assert (ZipCommon::isValidPath("some/dir/./another")); ++ assert (ZipCommon::isValidPath("some/dir/or/another/file.txt")); ++ assert (ZipCommon::isValidPath("s~me\\d.r\\.or..\\an..her\\file.txt")); ++ assert (ZipCommon::isValidPath("some\\dir\\or\\another")); ++ assert (ZipCommon::isValidPath("some\\dir\\or\\another\\file.txt")); ++ assert (ZipCommon::isValidPath("s~me\\d.r/.or..\\an..her\\file.txt")); ++ ++ assert (!ZipCommon::isValidPath("/../")); ++ assert (!ZipCommon::isValidPath("/")); ++ assert (!ZipCommon::isValidPath("\\..\\")); ++ assert (!ZipCommon::isValidPath("/..\\")); ++ assert (!ZipCommon::isValidPath("\\../")); ++ assert (!ZipCommon::isValidPath("..")); ++ assert (!ZipCommon::isValidPath("~/")); ++ assert (!ZipCommon::isValidPath("~/~")); ++ assert (!ZipCommon::isValidPath("/~")); ++ assert (!ZipCommon::isValidPath("/file.txt")); ++ assert (!ZipCommon::isValidPath("~/file.txt")); ++ assert (!ZipCommon::isValidPath("some/dir/or/../another/file.txt")); ++ assert (!ZipCommon::isValidPath("C:\\Windows\\system32")); ++} ++ ++ + void ZipTest::onDecompressError(const void* pSender, std::pair& info) + { + ++_errCnt; +@@ -209,7 +274,10 @@ CppUnit::Test* ZipTest::suite() + CppUnit_addTest(pSuite, ZipTest, testDecompressSingleFile); + CppUnit_addTest(pSuite, ZipTest, testDecompress); + CppUnit_addTest(pSuite, ZipTest, testDecompressFlat); ++ CppUnit_addTest(pSuite, ZipTest, testDecompressVuln); ++ CppUnit_addTest(pSuite, ZipTest, testDecompressFlatVuln); + CppUnit_addTest(pSuite, ZipTest, testCrcAndSizeAfterData); + CppUnit_addTest(pSuite, ZipTest, testCrcAndSizeAfterDataWithArchive); ++ CppUnit_addTest(pSuite, ZipTest, testValidPath); + return pSuite; + } +diff --git a/Zip/testsuite/src/ZipTest.h b/Zip/testsuite/src/ZipTest.h +index be76828..43ffc12 100644 +--- a/Zip/testsuite/src/ZipTest.h ++++ b/Zip/testsuite/src/ZipTest.h +@@ -50,10 +50,12 @@ public: + void testSkipSingleFile(); + void testDecompressSingleFile(); + void testDecompress(); ++ void testDecompressFlat(); ++ void testDecompressVuln(); ++ void testDecompressFlatVuln(); + void testCrcAndSizeAfterData(); + void testCrcAndSizeAfterDataWithArchive(); +- +- void testDecompressFlat(); ++ void testValidPath(); + + void setUp(); + void tearDown();