Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Sep 2015 20:23:25 +0000 (UTC)
From:      Mark Felder <feld@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r397079 - in head/archivers/p7zip: . files
Message-ID:  <201509162023.t8GKNPwk077399@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: feld
Date: Wed Sep 16 20:23:24 2015
New Revision: 397079
URL: https://svnweb.freebsd.org/changeset/ports/397079

Log:
  Apply patch to fix directory traversal vulnerability
  
  Submitted by:	ohauer
  MFH:		2015Q3
  Security:	CVE-2015-1038
  Security:	8f5c9dd6-5cac-11e5-9ad8-14dae9d210b8

Added:
  head/archivers/p7zip/files/patch-CVE-2015-1038   (contents, props changed)
Modified:
  head/archivers/p7zip/Makefile

Modified: head/archivers/p7zip/Makefile
==============================================================================
--- head/archivers/p7zip/Makefile	Wed Sep 16 20:21:09 2015	(r397078)
+++ head/archivers/p7zip/Makefile	Wed Sep 16 20:23:24 2015	(r397079)
@@ -3,7 +3,7 @@
 
 PORTNAME=	p7zip
 PORTVERSION=	9.38.1
-PORTREVISION?=	1
+PORTREVISION?=	2
 CATEGORIES=	archivers
 MASTER_SITES=	SF
 DISTNAME=	${PORTNAME}_${DISTVERSION}_src_all

Added: head/archivers/p7zip/files/patch-CVE-2015-1038
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/archivers/p7zip/files/patch-CVE-2015-1038	Wed Sep 16 20:23:24 2015	(r397079)
@@ -0,0 +1,283 @@
+Author: Ben Hutchings <ben@decadent.org.uk>
+Date: Tue, 19 May 2015 02:38:40 +0100
+Description: Delay creation of symlinks to prevent arbitrary file writes (CVE-2015-1038)
+Bug: http://sourceforge.net/p/p7zip/bugs/147/
+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.
+
+--- CPP/7zip/UI/Agent/Agent.cpp
++++ CPP/7zip/UI/Agent/Agent.cpp
+@@ -1215,7 +1215,7 @@ STDMETHODIMP CAgentFolder::Extract(const
+   HRESULT result = _agentSpec->GetArchive()->Extract(&realIndices.Front(),
+       realIndices.Size(), testMode, extractCallback);
+   if (result == S_OK)
+-    result = extractCallbackSpec->SetDirsTimes();
++    result = extractCallbackSpec->SetFinalAttribs();
+   return result;
+   COM_TRY_END
+ }
+--- CPP/7zip/UI/Client7z/Client7z.cpp
++++ CPP/7zip/UI/Client7z/Client7z.cpp
+@@ -222,8 +222,11 @@ private:
+   COutFileStream *_outFileStreamSpec;
+   CMyComPtr<ISequentialOutStream> _outFileStream;
+ 
++  CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks;
++
+ public:
+   void Init(IInArchive *archiveHandler, const FString &directoryPath);
++  HRESULT SetFinalAttribs();
+ 
+   UInt64 NumErrors;
+   bool PasswordIsDefined;
+@@ -441,11 +444,23 @@ STDMETHODIMP CArchiveExtractCallback::Se
+   }
+   _outFileStream.Release();
+   if (_extractMode && _processedFileInfo.AttribDefined)
+-    SetFileAttrib(_diskFilePath, _processedFileInfo.Attrib);
++    SetFileAttrib(_diskFilePath, _processedFileInfo.Attrib, &_delayedSymLinks);
+   PrintNewLine();
+   return S_OK;
+ }
+ 
++HRESULT CArchiveExtractCallback::SetFinalAttribs()
++{
++  HRESULT result = S_OK;
++
++  for (int i = 0; i != _delayedSymLinks.Size(); ++i)
++    if (!_delayedSymLinks[i].Create())
++      result = E_FAIL;
++
++  _delayedSymLinks.Clear();
++
++  return result;
++}
+ 
+ STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+ {
+@@ -912,6 +927,8 @@ int MY_CDECL main(int numArgs, const cha
+       // extractCallbackSpec->PasswordIsDefined = true;
+       // extractCallbackSpec->Password = L"1";
+       HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
++      if (result == S_OK)
++	result = extractCallbackSpec->SetFinalAttribs();
+       if (result != S_OK)
+       {
+         PrintError("Extract Error");
+--- CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
++++ CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+@@ -1083,7 +1083,7 @@ STDMETHODIMP CArchiveExtractCallback::Se
+     NumFiles++;
+ 
+   if (_extractMode && _fi.AttribDefined)
+-    SetFileAttrib(_diskFilePath, _fi.Attrib);
++    SetFileAttrib(_diskFilePath, _fi.Attrib, &_delayedSymLinks);
+   RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted));
+   return S_OK;
+   COM_TRY_END
+@@ -1149,8 +1149,9 @@ static int GetNumSlashes(const FChar *s)
+   }
+ }
+ 
+-HRESULT CArchiveExtractCallback::SetDirsTimes()
++HRESULT CArchiveExtractCallback::SetFinalAttribs()
+ {
++  HRESULT result = S_OK;
+   CRecordVector<CExtrRefSortPair> pairs;
+   pairs.ClearAndSetSize(_extractedFolderPaths.Size());
+   unsigned i;
+@@ -1187,5 +1188,12 @@ HRESULT CArchiveExtractCallback::SetDirs
+       (WriteATime && ATimeDefined) ? &ATime : NULL,
+       (WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+   }
+-  return S_OK;
++
++  for (int i = 0; i != _delayedSymLinks.Size(); ++i)
++    if (!_delayedSymLinks[i].Create())
++      result = E_FAIL;
++
++  _delayedSymLinks.Clear();
++
++  return result;
+ }
+--- CPP/7zip/UI/Common/ArchiveExtractCallback.h
++++ 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"
+@@ -213,6 +215,8 @@ class CArchiveExtractCallback:
+   bool _saclEnabled;
+   #endif
+ 
++  CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks;
++
+   void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
+   HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
+   HRESULT GetUnpackSize();
+@@ -293,7 +297,7 @@ public:
+     _baseParentFolder = indexInArc;
+   }
+ 
+-  HRESULT SetDirsTimes();
++  HRESULT SetFinalAttribs();
+ };
+ 
+ #endif
+--- CPP/7zip/UI/Common/Extract.cpp
++++ CPP/7zip/UI/Common/Extract.cpp
+@@ -170,7 +170,7 @@ static HRESULT DecompressArchive(
+   else
+     result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs);
+   if (result == S_OK && !options.StdInMode)
+-    result = ecs->SetDirsTimes();
++    result = ecs->SetFinalAttribs();
+   return callback->ExtractResult(result);
+ }
+ 
+--- CPP/Windows/FileDir.cpp
++++ CPP/Windows/FileDir.cpp
+@@ -343,7 +343,8 @@ static int convert_to_symlink(const char
+   return -1;
+ }
+ 
+-bool SetFileAttrib(CFSTR fileName, DWORD fileAttributes)
++bool SetFileAttrib(CFSTR fileName, DWORD fileAttributes,
++		   CObjectVector<CDelayedSymLink> *delayedSymLinks)
+ {
+   if (!fileName) {
+     SetLastError(ERROR_PATH_NOT_FOUND);
+@@ -375,7 +376,9 @@ bool SetFileAttrib(CFSTR fileName, DWORD
+      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("SetFileAttrib(%s,%d) : false-3\n",(const char *)name,fileAttributes)))
+           return false;
+         }
+@@ -885,6 +888,43 @@ bool CTempDir::Remove()
+   return !_mustBeDeleted;
+ }
+ 
++#ifdef ENV_UNIX
++
++CDelayedSymLink::CDelayedSymLink(const char * 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
++
+ }}}
+ 
+ 
+--- CPP/Windows/FileDir.h
++++ CPP/Windows/FileDir.h
+@@ -4,6 +4,7 @@
+ #define __WINDOWS_FILE_DIR_H
+ 
+ #include "../Common/MyString.h"
++#include "../Common/MyVector.h"
+ 
+ #include "FileIO.h"
+ 
+@@ -11,11 +12,14 @@ namespace NWindows {
+ namespace NFile {
+ namespace NDir {
+ 
++class CDelayedSymLink;
++
+ bool GetWindowsDir(FString &path);
+ bool GetSystemDir(FString &path);
+ 
+ bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime);
+-bool SetFileAttrib(CFSTR path, DWORD attrib);
++bool SetFileAttrib(CFSTR path, DWORD attrib,
++		   CObjectVector<CDelayedSymLink> *delayedSymLinks = 0);
+ bool MyMoveFile(CFSTR existFileName, CFSTR newFileName);
+ 
+ #ifndef UNDER_CE
+@@ -69,6 +73,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(const char * source);
++  bool Create();
++#else // !ENV_UNIX
++public:
++  CDelayedSymLink(const char * source) {}
++  bool Create() { return true; }
++#endif // ENV_UNIX
++};
++
+ #if !defined(UNDER_CE)
+ class CCurrentDirRestorer
+ {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509162023.t8GKNPwk077399>