Subject: [alpine-aports] [PATCH v3.1] main/p7zip: security upgrade - fixes #3831

From: Sergey Lukin <[email-masked]>
Date: Mon, 12 Dec 2016 12:45:42 +0000

CVE-2015-1038
CVE-2016-9296
---
 main/p7zip/APKBUILD            |  26 ++--
 main/p7zip/CVE-2015-1038.patch | 317 +++++++++++++++++++++++++++++++++++++++++
 main/p7zip/CVE-2016-9296.patch |  17 +++
 3 files changed, 352 insertions(+), 8 deletions(-)
 create mode 100644 main/p7zip/CVE-2015-1038.patch
 create mode 100644 main/p7zip/CVE-2016-9296.patch

diff --git a/main/p7zip/APKBUILD b/main/p7zip/APKBUILD
index 8f1a2a5..10c46ef 100644
--- a/main/p7zip/APKBUILD
+++ b/main/p7zip/APKBUILD
@@ -1,7 +1,8 @@
 # Maintainer: Natanael Copa <[email-masked]>
+# Contributor: Sergey Lukin <[email-masked]>
 pkgname=p7zip
 pkgver=9.20.1
-pkgrel=2
+pkgrel=3
 pkgdesc="A command-line port of the 7zip compression utility"
 url="http://p7zip.sourceforge.net"
 arch="all"
@@ -11,18 +12,21 @@ depends=
 makedepends="bash"
 #install=p7zip.install
 source="http://downloads.sourceforge.net/sourceforge/$pkgname/${pkgname}_${pkgver}_src_all.tar.bz2
-		p7zip-cc-cxx.patch"
+	p7zip-cc-cxx.patch
+	CVE-2015-1038.patch
+	CVE-2016-9296.patch
+	"
 
-_builddir="$srcdir"/${pkgname}_${pkgver}
+builddir="$srcdir"/${pkgname}_${pkgver}
 build() {
-	cd "$_builddir"
+	cd "$builddir"
 	patch -p1 -i ../p7zip-cc-cxx.patch || return 1
 	sed -i "s|usr/local|usr|g" makefile
 	make all3 OPTFLAGS="${CXXFLAGS}" || return 1
 }
 
 package() {
-	cd "$_builddir"
+	cd "$builddir"
 	make install DEST_HOME="$pkgdir"/usr DEST_MAN="$pkgdir"/usr/share/man \
 		DEST_SHARE_DOC="http://www.bugaco.com/7zip"
 
@@ -33,8 +37,14 @@ package() {
 }
 
 md5sums="bd6caaea567dc0d995c990c5cc883c89  p7zip_9.20.1_src_all.tar.bz2
-8e8f415267bb5db179e4a8ed75985244  p7zip-cc-cxx.patch"
+8e8f415267bb5db179e4a8ed75985244  p7zip-cc-cxx.patch
+7277c65b33493f23e6bed822088f9202  CVE-2015-1038.patch
+8242ea6835b180546a4bf798a94d71bb  CVE-2016-9296.patch"
 sha256sums="49557e7ffca08100f9fc687f4dfc5aea703ca207640c76d9dee7b66f03cb4782  p7zip_9.20.1_src_all.tar.bz2
-dc77487a62591a4e5ec4ffd2c6340f124295f3b11e2040455deed37c5723660c  p7zip-cc-cxx.patch"
+dc77487a62591a4e5ec4ffd2c6340f124295f3b11e2040455deed37c5723660c  p7zip-cc-cxx.patch
+0a3071e2d479c455738a9d6d52dc47f92805a0ac021263755af21c3deb96480f  CVE-2015-1038.patch
+ff0e104a28ea055a31c78ccb817614e1a2ae252c2e87aab5da4c9ce3fcfcaa44  CVE-2016-9296.patch"
 sha512sums="7bb8a276aaefc4a83364e45633c48527de44c6b1205344f3356db570582f30f81d82a94938c99a7ad193587b584cc1c03219c28249de40018bdaee6c3b2a022a  p7zip_9.20.1_src_all.tar.bz2
-476f6b5c6b617868afbecc912dcef6bea3dfc7e0476e169bc43d830ef33229bd6895c963f8481f31f897390aa07ed77ec8f02f4e36b2dd8619135d11d28863fa  p7zip-cc-cxx.patch"
+476f6b5c6b617868afbecc912dcef6bea3dfc7e0476e169bc43d830ef33229bd6895c963f8481f31f897390aa07ed77ec8f02f4e36b2dd8619135d11d28863fa  p7zip-cc-cxx.patch
+121925d618becb9a42818b2d9bfa74869071ce589dfdea8039511d9a5296da40a575bedd88f59c37710007d3381671c67750f023998c3b3b1d892a830d4d6ca2  CVE-2015-1038.patch
+ecb718864aed9c13781ed076de9dea88eea75226d53904cd98ec048d9731843c741403759815964706483f379ef304cb9bb5fca8c1202d580c211ae679607065  CVE-2016-9296.patch"
diff --git a/main/p7zip/CVE-2015-1038.patch b/main/p7zip/CVE-2015-1038.patch
new file mode 100644
index 0000000..1013b73
--- /dev/null
+++ b/main/p7zip/CVE-2015-1038.patch
@@ -0,0 +1,317 @@
+https://sourceforge.net/p/p7zip/bugs/147/
+https://sourceforge.net/p/p7zip/bugs/_discuss/thread/17901103/2f9c/attachment/CVE-2015-1038.patch
+
+Author: Ben Hutchings <[email-masked]>
+Date: Tue, 19 May 2015 02:38:40 +0100
+Description: Delay creation of symlinks to prevent arbitrary file writes (CVE-2015-1038)
+Bug-Debian: https://bugs.debian.org/774660
+
+Alexander Cherepanov discovered that 7zip is susceptible to a
+directory traversal vulnerability.  While extracting an archive, it
+will extract symlinks and then follow them if they are referenced in
+further entries.  This can be exploited by a rogue archive to write
+files outside the current directory.
+
+We have to create placeholder files (which we already do) and delay
+creating symlinks until the end of extraction.
+
+Due to the possibility of anti-items (deletions) in the archive, it is
+possible for placeholders to be deleted and replaced before we create
+the symlinks.  It's not clear that this can be used for mischief, but
+GNU tar guards against similar problems by checking that the placeholder
+still exists and is the same inode.  XXX It also checks 'birth time' but
+this isn't portable.  We can probably get away with comparing ctime
+since we don't support hard links.
+
+--- a/CPP/7zip/UI/Agent/Agent.cpp
++++ b/CPP/7zip/UI/Agent/Agent.cpp
+@@ -424,6 +424,8 @@ STDMETHODIMP CAgentFolder::Extract(const
+   CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+   UStringVector pathParts;
+   CProxyFolder *currentProxyFolder = _proxyFolderItem;
++  HRESULT res;
++
+   while (currentProxyFolder->Parent)
+   {
+     pathParts.Insert(0, currentProxyFolder->Name);
+@@ -445,8 +447,11 @@ STDMETHODIMP CAgentFolder::Extract(const
+       (UInt64)(Int64)-1);
+   CUIntVector realIndices;
+   GetRealIndices(indices, numItems, realIndices);
+-  return _agentSpec->GetArchive()->Extract(&realIndices.Front(),
++  res = _agentSpec->GetArchive()->Extract(&realIndices.Front(),
+       realIndices.Size(), testMode, extractCallback);
++  if (res == S_OK && !extractCallbackSpec->CreateSymLinks())
++    res = E_FAIL;
++  return res;
+   COM_TRY_END
+ }
+ 
+--- a/CPP/7zip/UI/Agent/ArchiveFolder.cpp
++++ b/CPP/7zip/UI/Agent/ArchiveFolder.cpp
+@@ -20,6 +20,8 @@ STDMETHODIMP CAgentFolder::CopyTo(const
+   CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+   UStringVector pathParts;
+   CProxyFolder *currentProxyFolder = _proxyFolderItem;
++  HRESULT res;
++
+   while (currentProxyFolder->Parent)
+   {
+     pathParts.Insert(0, currentProxyFolder->Name);
+@@ -46,8 +48,11 @@ STDMETHODIMP CAgentFolder::CopyTo(const
+       (UInt64)(Int64)-1);
+   CUIntVector realIndices;
+   GetRealIndices(indices, numItems, realIndices);
+-  return _agentSpec->GetArchive()->Extract(&realIndices.Front(),
++  res = _agentSpec->GetArchive()->Extract(&realIndices.Front(),
+       realIndices.Size(), BoolToInt(false), extractCallback);
++  if (res == S_OK && !extractCallbackSpec->CreateSymLinks())
++    res = E_FAIL;
++  return res;
+   COM_TRY_END
+ }
+ 
+--- a/CPP/7zip/UI/Client7z/Client7z.cpp
++++ b/CPP/7zip/UI/Client7z/Client7z.cpp
+@@ -197,8 +197,11 @@ private:
+   COutFileStream *_outFileStreamSpec;
+   CMyComPtr<ISequentialOutStream> _outFileStream;
+ 
++  CObjectVector<NWindows::NFile::NDirectory::CDelayedSymLink> _delayedSymLinks;
++
+ public:
+   void Init(IInArchive *archiveHandler, const UString &directoryPath);
++  bool CreateSymLinks();
+ 
+   UInt64 NumErrors;
+   bool PasswordIsDefined;
+@@ -392,11 +395,22 @@ STDMETHODIMP CArchiveExtractCallback::Se
+   }
+   _outFileStream.Release();
+   if (_extractMode && _processedFileInfo.AttribDefined)
+-    NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attrib);
++    NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attrib, &_delayedSymLinks);
+   PrintNewLine();
+   return S_OK;
+ }
+ 
++bool CArchiveExtractCallback::CreateSymLinks()
++{
++  bool success = true;
++
++  for (int i = 0; i != _delayedSymLinks.Size(); ++i)
++    success &= _delayedSymLinks[i].Create();
++
++  _delayedSymLinks.Clear();
++
++  return success;
++}
+ 
+ STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+ {
+--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
++++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+@@ -453,12 +453,24 @@ STDMETHODIMP CArchiveExtractCallback::Se
+     NumFiles++;
+ 
+   if (_extractMode && _fi.AttribDefined)
+-    NFile::NDirectory::MySetFileAttributes(_diskFilePath, _fi.Attrib);
++    NFile::NDirectory::MySetFileAttributes(_diskFilePath, _fi.Attrib, &_delayedSymLinks);
+   RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted));
+   return S_OK;
+   COM_TRY_END
+ }
+ 
++bool CArchiveExtractCallback::CreateSymLinks()
++{
++  bool success = true;
++
++  for (int i = 0; i != _delayedSymLinks.Size(); ++i)
++    success &= _delayedSymLinks[i].Create();
++
++  _delayedSymLinks.Clear();
++
++  return success;
++}
++
+ /*
+ STDMETHODIMP CArchiveExtractCallback::GetInStream(
+     const wchar_t *name, ISequentialInStream **inStream)
+--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h
++++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
+@@ -6,6 +6,8 @@
+ #include "Common/MyCom.h"
+ #include "Common/Wildcard.h"
+ 
++#include "Windows/FileDir.h"
++
+ #include "../../IPassword.h"
+ 
+ #include "../../Common/FileStreams.h"
+@@ -83,6 +85,8 @@ class CArchiveExtractCallback:
+   UInt64 _packTotal;
+   UInt64 _unpTotal;
+ 
++  CObjectVector<NWindows::NFile::NDirectory::CDelayedSymLink> _delayedSymLinks;
++
+   void CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath);
+   HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
+   HRESULT GetUnpackSize();
+@@ -138,6 +142,7 @@ public:
+       const UStringVector &removePathParts,
+       UInt64 packSize);
+ 
++  bool CreateSymLinks();
+ };
+ 
+ #endif
+--- a/CPP/7zip/UI/Common/Extract.cpp
++++ b/CPP/7zip/UI/Common/Extract.cpp
+@@ -96,6 +96,9 @@ static HRESULT DecompressArchive(
+   else
+     result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec);
+ 
++  if (result == S_OK && !extractCallbackSpec->CreateSymLinks())
++    result = E_FAIL;
++
+   return callback->ExtractResult(result);
+ }
+ 
+--- a/CPP/Windows/FileDir.cpp
++++ b/CPP/Windows/FileDir.cpp
+@@ -453,9 +453,10 @@ bool SetDirTime(LPCWSTR fileName, const
+ }
+ 
+ #ifndef _UNICODE
+-bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes)
++bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes,
++			 CObjectVector<CDelayedSymLink> *delayedSymLinks)
+ {  
+-  return MySetFileAttributes(UnicodeStringToMultiByte(fileName, CP_ACP), fileAttributes);
++  return MySetFileAttributes(UnicodeStringToMultiByte(fileName, CP_ACP), fileAttributes, delayedSymLinks);
+ }
+ 
+ bool MyRemoveDirectory(LPCWSTR pathName)
+@@ -488,7 +489,8 @@ static int convert_to_symlink(const char
+   return -1;
+ }
+ 
+-bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes)
++bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes,
++			 CObjectVector<CDelayedSymLink> *delayedSymLinks)
+ {
+   if (!fileName) {
+     SetLastError(ERROR_PATH_NOT_FOUND);
+@@ -520,7 +522,9 @@ bool MySetFileAttributes(LPCTSTR fileNam
+      stat_info.st_mode = fileAttributes >> 16;
+ #ifdef ENV_HAVE_LSTAT
+      if (S_ISLNK(stat_info.st_mode)) {
+-        if ( convert_to_symlink(name) != 0) {
++        if (delayedSymLinks)
++          delayedSymLinks->Add(CDelayedSymLink(name));
++        else if ( convert_to_symlink(name) != 0) {
+           TRACEN((printf("MySetFileAttributes(%s,%d) : false-3\n",name,fileAttributes)))
+           return false;
+         }
+@@ -924,4 +928,41 @@ bool CTempDirectory::Create(LPCTSTR pref
+ }
+ 
+ 
++#ifdef ENV_UNIX
++
++CDelayedSymLink::CDelayedSymLink(LPCSTR source)
++  : _source(source)
++{
++  struct stat st;
++
++  if (lstat(_source, &st) == 0) {
++    _dev = st.st_dev;
++    _ino = st.st_ino;
++  } else {
++    _dev = 0;
++  }
++}
++
++bool CDelayedSymLink::Create()
++{
++  struct stat st;
++
++  if (_dev == 0) {
++    errno = EPERM;
++    return false;
++  }
++  if (lstat(_source, &st) != 0)
++    return false;
++  if (_dev != st.st_dev || _ino != st.st_ino) {
++    // Placeholder file has been overwritten or moved by another
++    // symbolic link creation
++    errno = EPERM;
++    return false;
++  }
++
++  return convert_to_symlink(_source) == 0;
++}
++
++#endif // ENV_UNIX
++
+ }}}
+--- a/CPP/Windows/FileDir.h
++++ b/CPP/Windows/FileDir.h
+@@ -4,6 +4,7 @@
+ #define __WINDOWS_FILEDIR_H
+ 
+ #include "../Common/MyString.h"
++#include "../Common/MyVector.h"
+ #include "Defs.h"
+ 
+ /* GetFullPathName for 7zAES.cpp */
+@@ -13,11 +14,15 @@ namespace NWindows {
+ namespace NFile {
+ namespace NDirectory {
+ 
++class CDelayedSymLink;
++
+ bool SetDirTime(LPCWSTR fileName, const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime);
+ 
+-bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes);
++bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes,
++			 CObjectVector<CDelayedSymLink> *delayedSymLinks = 0);
+ #ifndef _UNICODE
+-bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes);
++bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes,
++			 CObjectVector<CDelayedSymLink> *delayedSymLinks = 0);
+ #endif
+ 
+ bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName);
+@@ -80,6 +85,31 @@ public:
+   bool Remove();
+ };
+ 
++// Symbolic links must be created last so that they can't be used to
++// create or overwrite files above the extraction directory.
++class CDelayedSymLink
++{
++#ifdef ENV_UNIX
++  // Where the symlink should be created.  The target is specified in
++  // the placeholder file.
++  AString _source;
++
++  // Device and inode of the placeholder file.  Before creating the
++  // symlink, we must check that these haven't been changed by creation
++  // of another symlink.
++  dev_t _dev;
++  ino_t _ino;
++
++public:
++  explicit CDelayedSymLink(LPCSTR source);
++  bool Create();
++#else // !ENV_UNIX
++public:
++  CDelayedSymLink(LPCSTR source) {}
++  bool Create() { return true; }
++#endif // ENV_UNIX
++};
++
+ #ifdef _UNICODE
+ typedef CTempFile CTempFileW;
+ #endif
diff --git a/main/p7zip/CVE-2016-9296.patch b/main/p7zip/CVE-2016-9296.patch
new file mode 100644
index 0000000..06c4c45
--- /dev/null
+++ b/main/p7zip/CVE-2016-9296.patch
@@ -0,0 +1,17 @@
+CVE-2016-9296
+https://sourceforge.net/p/p7zip/bugs/185/
+https://sourceforge.net/p/p7zip/discussion/383043/thread/648d34db/
+
+
+--- p7zip_9.38.1.orig/CPP/7zip/Archive/7z/7zIn.cpp
++++ p7zip_9.38.1/CPP/7zip/Archive/7z/7zIn.cpp
+@@ -1142,7 +1142,8 @@
+       if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i])
+         ThrowIncorrect();
+   }
+-  HeadersSize += folders.PackPositions[folders.NumPackStreams];
++  if (folders.PackPositions) //this line is fixing CVE-2016-9296 (https://sourceforge.net/p/p7zip/bugs/185, https://sourceforge.net/p/p7zip/discussion/383043/thread/648d34db/?limit=25#d9d7)
++    HeadersSize += folders.PackPositions[folders.NumPackStreams];
+   return S_OK;
+ }
+ 
-- 
2.2.1

---
Unsubscribe:  [email-masked]
Help:         [email-masked]
---