[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#900920: stretch-pu: package freedink-dfarc/3.12-1+deb9u1



Package: release.debian.org
User: release.debian.org@packages.debian.org
Usertags: pu
Tags: stretch
Severity: normal

Hi,

Please consider this update to freedink-dfarc for stretch.
It fixes a security issue that can overwrite arbitrary user files.
Sending to stable following security team's directions from 2018-06-01.

Attached is the debdiff.
Let me know if I can push the upload to stable.

Cheers!
Sylvain

diff -Nru freedink-dfarc-3.12/debian/changelog freedink-dfarc-3.12/debian/changelog
--- freedink-dfarc-3.12/debian/changelog	2014-10-16 23:04:34.000000000 +0200
+++ freedink-dfarc-3.12/debian/changelog	2018-06-05 21:41:38.000000000 +0200
@@ -1,3 +1,11 @@
+freedink-dfarc (3.12-1+deb9u1) stable; urgency=high
+
+  * Fix directory traversal in D-Mod extractor (CVE-2018-0496)
+  * Upload to 'stable' as security team rejected a DSA to
+    'stretch-security' (no justification)
+
+ -- Sylvain Beucler <beuc@debian.org>  Tue, 05 Jun 2018 21:41:38 +0200
+
 freedink-dfarc (3.12-1) unstable; urgency=medium
 
   * New Upstream Release
diff -Nru freedink-dfarc-3.12/debian/patches/CVE-2018-0496.patch freedink-dfarc-3.12/debian/patches/CVE-2018-0496.patch
--- freedink-dfarc-3.12/debian/patches/CVE-2018-0496.patch	1970-01-01 01:00:00.000000000 +0100
+++ freedink-dfarc-3.12/debian/patches/CVE-2018-0496.patch	2018-06-05 21:41:38.000000000 +0200
@@ -0,0 +1,232 @@
+Description: Fix directory traversal in D-Mod extrator (CVE-2018-0496)
+Author: Sylvain Beucler
+Origin: upstream
+Last-Update: 2018-06-05
+
+commit 40cc957f52e772f45125126439ba9333cf2d2998
+Author: Sylvain Beucler <beuc@beuc.net>
+Date:   Tue Jun 5 23:07:56 2018 +0200
+
+    Fix directory traversal in D-Mod extractor (CVE-2018-0496)
+
+diff --git a/src/InstallVerifyFrame.cpp b/src/InstallVerifyFrame.cpp
+index 64964e1..494ba53 100644
+--- a/src/InstallVerifyFrame.cpp
++++ b/src/InstallVerifyFrame.cpp
+@@ -3,7 +3,7 @@
+ 
+  * Copyright (C) 2004  Andrew Reading
+  * Copyright (C) 2005, 2006  Dan Walma
+- * Copyright (C) 2008  Sylvain Beucler
++ * Copyright (C) 2008, 2018  Sylvain Beucler
+ 
+  * This file is part of GNU FreeDink
+ 
+@@ -55,7 +55,10 @@ InstallVerifyFrame::InstallVerifyFrame(const wxString& lDmodFilePath)
+     {
+       // Prepare the tar file for reading
+       Tar lTar(mTarFilePath);
+-      lTar.ReadHeaders();
++      if (lTar.ReadHeaders() == 1) {
++        this->EndModal(wxID_CANCEL);
++        return;
++      }
+      
+       // Get and display the dmod description
+       wxString lDmodDescription = lTar.getmDmodDescription();
+@@ -122,7 +125,20 @@ void InstallVerifyFrame::onInstall(wxCommandEvent &Event)
+     destdir = mConfig->mDModDir;
+ 
+   Tar lTar(mTarFilePath);
+-  lTar.ReadHeaders();
++  if (lTar.ReadHeaders() == 1) {
++    this->EndModal(wxID_CANCEL);
++    return;
++  }
++
++  if (wxDirExists(destdir + wxFileName::GetPathSeparator() + lTar.getInstalledDmodDirectory())) {
++    wxString question;
++    question.Printf(_("Directory '%s' already exists. Continue?"), lTar.getInstalledDmodDirectory());
++    int lResult = wxMessageBox(question, _("DFArc - Installing"),
++			       wxYES_NO | wxICON_WARNING, this);
++    if (lResult == wxNO)
++      return;
++  }
++
+   int lError = lTar.Extract(destdir, &lInstallProgress);
+   if (lError == 0)
+     {
+diff --git a/src/Tar.cpp b/src/Tar.cpp
+index b919ae7..8147b8a 100644
+--- a/src/Tar.cpp
++++ b/src/Tar.cpp
+@@ -3,7 +3,7 @@
+ 
+  * Copyright (C) 2004  Andrew Reading
+  * Copyright (C) 2005, 2006  Dan Walma
+- * Copyright (C) 2008, 2014  Sylvain Beucler
++ * Copyright (C) 2008, 2014, 2018  Sylvain Beucler
+ 
+  * This file is part of GNU FreeDink
+ 
+@@ -31,6 +31,7 @@
+ #include <wx/intl.h>
+ #include <wx/log.h>
+ #include <wx/filename.h>
++#include <wx/tokenzr.h>
+ 
+ #include <math.h>
+ #include <ext/stdio_filebuf.h>
+@@ -427,7 +428,15 @@ int Tar::ReadHeaders( void )
+       wxString lPath(lRecord.Name, wxConvUTF8);
+       if (mInstalledDmodDirectory.Length() == 0)
+         {
+-	  mInstalledDmodDirectory = lPath.SubString( 0, lPath.Find( '/' ) );
++	  // Security: ensure the D-Mod directory is non-empty
++	  wxString firstDir = GetFirstDir(lPath);
++	  if (firstDir.IsSameAs("", true) || firstDir.IsSameAs("..", true) || firstDir.IsSameAs("dink", true))
++            {
++	      wxLogError(_("Error: invalid D-Mod directory.  Stopping."));
++              return 1;
++            }
++          mInstalledDmodDirectory = firstDir;
++
+ 	  lDmodDizPath = mInstalledDmodDirectory + _T("dmod.diz");
+ 	  lDmodDizPath.LowerCase();
+         }
+@@ -472,10 +481,6 @@ int Tar::Extract(wxString destdir, wxProgressDialog* aProgressDialog)
+     wxString strBuf;
+     int lError = 0;
+ 
+-    // Remember current directory
+-    wxString strCwd = ::wxGetCwd();
+-
+-
+     // Open the file here so it doesn't error after changing.
+     wxFile wx_In(mFilePath, wxFile::read);
+ 
+@@ -495,8 +500,6 @@ int Tar::Extract(wxString destdir, wxProgressDialog* aProgressDialog)
+ 	wxLogFatalError(_("Error: Cannot create directory '%s'.  Cannot extract data."), destdir.c_str());
+ 	throw;
+       }
+-    // Move to the directory.
+-    ::wxSetWorkingDirectory(destdir);
+ 
+     // Put the data in the directories.
+     __gnu_cxx::stdio_filebuf<char> filebuf(wx_In.fd(), std::ios::in);
+@@ -507,10 +510,6 @@ int Tar::Extract(wxString destdir, wxProgressDialog* aProgressDialog)
+     }
+     wx_In.Close();
+ 
+-
+-    // We're done.  Move back.
+-    ::wxSetWorkingDirectory(strCwd);
+-    
+     return lError;
+ }
+ 
+@@ -527,10 +526,6 @@ int Tar::ExtractData(std::istream& aTarStreamIn, wxString destdir, wxProgressDia
+     aTarStreamIn.seekg(0, std::ios::beg);
+     lTotalBytes = lEnd - static_cast<unsigned long>(aTarStreamIn.tellg());
+ 
+-    // Move into the extract dir.
+-    wxString lPreviousWorkingDirectory(::wxGetCwd());
+-    ::wxSetWorkingDirectory(destdir);
+-
+     // Extract the files.
+     int ebufsiz = 8192;
+     char buffer[ebufsiz];
+@@ -543,7 +538,16 @@ int Tar::ExtractData(std::istream& aTarStreamIn, wxString destdir, wxProgressDia
+ 		    /* Attempt convertion from latin-1 if not valid UTF-8 */
+ 		    lCurrentFilePath = wxString(lCurrentTarRecord.Name, wxConvISO8859_1);
+ 		  }
+-		wxString lCurrentDirectory(lCurrentFilePath.substr(0, lCurrentFilePath.find_last_of('/')));
++        // Security: check if archive tries to jump out of destination directory
++        if (IsPathInsecure(lCurrentFilePath))
++        {
++            wxLogError(_("Error: Insecure filename: '%s'.  Stopping."), lCurrentFilePath);
++            lError = 1;
++            break;
++        }
++        // Security: ensure full, non-relative path, under destdir/
++        lCurrentFilePath = destdir + wxFileName::GetPathSeparator() + lCurrentFilePath;
++        wxString lCurrentDirectory = lCurrentFilePath.substr(0, lCurrentFilePath.find_last_of("/\\"));
+ 
+         // Odd bad file problem...
+ 	if (lCurrentFilePath.compare(_T("\xFF")) == 0) // "ÿ"
+@@ -612,7 +616,6 @@ int Tar::ExtractData(std::istream& aTarStreamIn, wxString destdir, wxProgressDia
+         }
+     }
+     aProgressDialog->Update(100, _("Done."));
+-    ::wxSetWorkingDirectory(lPreviousWorkingDirectory);
+     return lError;
+ }
+ 
+@@ -687,3 +690,45 @@ int Tar::RoundTo512(int n)
+         return (n - (n % 512)) + 512;
+     }
+ }
++
++wxString Tar::GetFirstDir(wxString path) {
++    wxString firstDir = "";
++    wxString previousDir = "";
++    // tokenizer never returns empty strings + distinguish dir// and a/$
++    if (path.EndsWith("/") || path.EndsWith("\\"))
++        path += "dummy";
++    wxStringTokenizer tokenizer(path, "/\\", wxTOKEN_STRTOK);
++    while (tokenizer.HasMoreTokens()) {
++        wxString curDir = tokenizer.GetNextToken();
++        if (curDir == '.')
++	    continue;
++        if (previousDir != "") {
++	  firstDir = previousDir;
++	  break;
++	}
++        previousDir = curDir;
++    }
++    return firstDir;
++}
++
++// Security: check if archive tries to jump out of destination directory
++bool Tar::IsPathInsecure(wxString path) {
++    // Avoid leading slashes (even if we preprend destdir)
++    if (path[0] == '/' || path[0] == '\\')
++        return true;
++    // Avoid ':' since wxFileName::Mkdir silently normalizes
++    // e.g. C:\test1\C:\test2 to C:\test2
++    if (path.Contains(":"))
++        return true;
++    // Ensure all files reside in the same subdirectory
++    if (GetFirstDir(path) != mInstalledDmodDirectory)
++        return true;
++    // Ensure there's no '..' path element
++    wxStringTokenizer tokenizer(path, "/\\");
++    while (tokenizer.HasMoreTokens()) {
++        wxString token = tokenizer.GetNextToken();
++        if (token == "..")
++            return true;
++    }
++    return false;
++}
+diff --git a/src/Tar.hpp b/src/Tar.hpp
+index f612580..62d7147 100644
+--- a/src/Tar.hpp
++++ b/src/Tar.hpp
+@@ -3,7 +3,7 @@
+ 
+  * Copyright (C) 2004  Andrew Reading
+  * Copyright (C) 2005, 2006  Dan Walma
+- * Copyright (C) 2008  Sylvain Beucler
++ * Copyright (C) 2008, 2018  Sylvain Beucler
+ 
+  * This file is part of GNU FreeDink
+ 
+@@ -88,6 +88,8 @@ private:
+   bool VerifyChecksum(TarHeader *Header);
+   bool CreateReal(const wxString& aFolderName, double *compression_ratio, wxProgressDialog* aProgressDialog);
+   int ExtractData(std::istream &f_In, wxString destdir, wxProgressDialog* aProgressDialog);
++  wxString GetFirstDir(wxString path);
++  bool IsPathInsecure(wxString path);
+   
+   // True if the proper constructor was used.  The compression method
+   // will not screw up if this flag is set to true.
diff -Nru freedink-dfarc-3.12/debian/patches/series freedink-dfarc-3.12/debian/patches/series
--- freedink-dfarc-3.12/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
+++ freedink-dfarc-3.12/debian/patches/series	2018-05-31 22:24:42.000000000 +0200
@@ -0,0 +1 @@
+CVE-2018-0496.patch

Reply to: