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

Bug#742882: apt: Does not support LFS .deb packages on 32-bit systems



Control: tags -1 patch

Hi!

On Fri, 2014-03-28 at 14:42:41 +0100, Guillem Jover wrote:
> Package: apt
> Version: 0.9.16.1
> Severity: normal

> Somewhat recently apt was fixed to add LFS for the ar containers, but
> the tarballs within are still not LFS-safe on 32-bit systems.
> 
> Here's a list of issues I've spotted by code staring, I've not tested
> anything, and I should create LFS .deb tests for the tar members too
> in dpkg/pkg-tests.git.
> 
> Types (should be off_t, long long or any other 64-bit-safe type):
> 
>  - ARArchive::Member::Start.
>  - pkgDirStream::Size.
>  - pkgDirStream::Process(), Size and Pos arguments.
>  - ExtractTar::Go(), Size and Read variables, and cast truncation.
> 
> The following I guess more out of correctness, as I don't expect to
> see > 4 GiB control files around:
> 
>  - debDebFile::MemControlExtract::Length.
>  - debDebFile::MemControlExtract::Process(), Size and Pos arguments.
>  - debDebFile::MemControlExtract::TakeControl(), Size argument.
> 
> These are minor issues, and would be related to either bogus or
> malicious archives, but probably still good to handle:
> 
>  - ExtractTar::Go(), GNU_LongLink and GNU_LongName short Length which
>    would truncate from Itm.Size.

Ok, here's a first rough go at a patch. It breaks ABI, and just noticed
an ABI breaking release was recently uploaded to experimental. :(

Just wanted to publish it for now, in case your policy allows to merge
this in the ABI breaking release. Otherwise I could rework it to stage
the change in preprocessor macros in a similar way as how you seem to
handle these. I've only test-built it though.

Some other comments:

 * MaxInSize is not used anywhere, but I guess it could be useful to
   handle bundled archives. Otherwise it might make sense to just
   remove it, and the arg in the constructor.
 * Also changed the in-core loaders because they are virtuals.
 * The in-core handling could possibly check for huge sizes before
   trying to allocate stuff, but it should fail with
   ENOMEM or std::bad_alloc otherwise I guess.
 * The patch description is rather terse…

Thanks,
Guillem
From 78a9cbf46aa0d073b8f88d949df5495f73a4fa23 Mon Sep 17 00:00:00 2001
From: Guillem Jover <guillem@debian.org>
Date: Wed, 2 Jul 2014 03:12:00 +0200
Subject: [PATCH 1/2] Add new Base256ToNum long long overload function

---
 apt-pkg/contrib/strutl.cc     | 19 ++++++++++++++++++-
 apt-pkg/contrib/strutl.h      |  1 +
 debian/libapt-pkg4.12.symbols |  1 +
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index ce69c7a..0f48860 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -1046,7 +1046,7 @@ bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base
 // ---------------------------------------------------------------------
 /* This is used in decoding the 256bit encoded fixed length fields in
    tar files */
-bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len)
+bool Base256ToNum(const char *Str,unsigned long long &Res,unsigned int Len)
 {
    if ((Str[0] & 0x80) == 0)
       return false;
@@ -1059,6 +1059,23 @@ bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len)
    }
 }
 									/*}}}*/
+// Base256ToNum - Convert a fixed length binary to a number             /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used in decoding the 256bit encoded fixed length fields in
+   tar files */
+bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len)
+{
+   unsigned long long Num;
+   bool rc;
+
+   rc = Base256ToNum(Str, Num, Len);
+   Res = Num;
+   if (Res != Num)
+      return false;
+
+   return rc;
+}
+									/*}}}*/
 // HexDigit - Convert a hex character into an integer			/*{{{*/
 // ---------------------------------------------------------------------
 /* Helper for Hex2Num */
diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h
index 185cdc3..5733fd6 100644
--- a/apt-pkg/contrib/strutl.h
+++ b/apt-pkg/contrib/strutl.h
@@ -72,6 +72,7 @@ bool ReadMessages(int Fd, std::vector<std::string> &List);
 bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0);
 bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base = 0);
 bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len);
+bool Base256ToNum(const char *Str,unsigned long long &Res,unsigned int Len);
 bool Hex2Num(const std::string &Str,unsigned char *Num,unsigned int Length);
 
 // input changing string split
diff --git a/debian/libapt-pkg4.12.symbols b/debian/libapt-pkg4.12.symbols
index 3fa128c..f99d3dd 100644
--- a/debian/libapt-pkg4.12.symbols
+++ b/debian/libapt-pkg4.12.symbols
@@ -22,6 +22,7 @@ libapt-pkg.so.4.12 libapt-pkg4.12 #MINVER#
  (c++)"StringToBool(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)@Base" 0.8.0
  (c++)"UnmountCdrom(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 0.8.0
  (c++)"_GetErrorObj()@Base" 0.8.0
+ (c++)"Base256ToNum(char const*, unsigned long long&, unsigned int)@Base" 1.0.5
  (c++)"pkgFixBroken(pkgDepCache&)@Base" 0.8.0
  (c++)"DeQuoteString(__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, __gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)@Base" 0.8.0
  (c++)"DeQuoteString(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.8.0
-- 
2.0.1

From 6f85a5134282862fc87126cb57ed6ae1becdf6fc Mon Sep 17 00:00:00 2001
From: Guillem Jover <guillem@debian.org>
Date: Wed, 2 Jul 2014 03:10:21 +0200
Subject: [PATCH 2/2] Fix ar and tar code to be LFS-safe

This is an ABI break.

Closes: #742882
---
 apt-inst/contrib/arfile.h       |  2 +-
 apt-inst/contrib/extracttar.cc  | 13 ++++++-------
 apt-inst/contrib/extracttar.h   |  4 ++--
 apt-inst/deb/debfile.cc         |  4 ++--
 apt-inst/deb/debfile.h          |  4 ++--
 apt-inst/dirstream.h            |  4 ++--
 cmdline/apt-extracttemplates.cc |  2 +-
 cmdline/apt-extracttemplates.h  |  4 ++--
 debian/libapt-inst1.5.symbols   |  8 ++++----
 9 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/apt-inst/contrib/arfile.h b/apt-inst/contrib/arfile.h
index 0f62a34..5aa38ae 100644
--- a/apt-inst/contrib/arfile.h
+++ b/apt-inst/contrib/arfile.h
@@ -61,7 +61,7 @@ struct ARArchive::Member
    unsigned long long Size;
    
    // Location of the data.
-   unsigned long Start;
+   unsigned long long Start;
    Member *Next;
    
    Member() : Start(0), Next(0) {};
diff --git a/apt-inst/contrib/extracttar.cc b/apt-inst/contrib/extracttar.cc
index 0ba3f05..2c86d0d 100644
--- a/apt-inst/contrib/extracttar.cc
+++ b/apt-inst/contrib/extracttar.cc
@@ -60,9 +60,8 @@ struct ExtractTar::TarHeader
 // ExtractTar::ExtractTar - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-ExtractTar::ExtractTar(FileFd &Fd,unsigned long Max,string DecompressionProgram) : File(Fd), 
-                         MaxInSize(Max), DecompressProg(DecompressionProgram)
-
+ExtractTar::ExtractTar(FileFd &Fd,unsigned long long Max,string DecompressionProgram)
+	: File(Fd), MaxInSize(Max), DecompressProg(DecompressionProgram)
 {
    GZPid = -1;
    Eof = false;
@@ -267,7 +266,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
 
 	 case GNU_LongLink:
 	 {
-	    unsigned long Length = Itm.Size;
+	    unsigned long long Length = Itm.Size;
 	    unsigned char Block[512];
 	    while (Length > 0)
 	    {
@@ -286,7 +285,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
 	 
 	 case GNU_LongName:
 	 {
-	    unsigned long Length = Itm.Size;
+	    unsigned long long Length = Itm.Size;
 	    unsigned char Block[512];
 	    while (Length > 0)
 	    {
@@ -315,11 +314,11 @@ bool ExtractTar::Go(pkgDirStream &Stream)
 	    return false;
       
       // Copy the file over the FD
-      unsigned long Size = Itm.Size;
+      unsigned long long Size = Itm.Size;
       while (Size != 0)
       {
 	 unsigned char Junk[32*1024];
-	 unsigned long Read = min(Size,(unsigned long)sizeof(Junk));
+	 unsigned long Read = min(Size, (unsigned long long)sizeof(Junk));
 	 if (InFd.Read(Junk,((Read+511)/512)*512) == false)
 	    return false;
 	 
diff --git a/apt-inst/contrib/extracttar.h b/apt-inst/contrib/extracttar.h
index 4b29df3..472e018 100644
--- a/apt-inst/contrib/extracttar.h
+++ b/apt-inst/contrib/extracttar.h
@@ -39,7 +39,7 @@ class ExtractTar
                   GNU_LongLink = 'K',GNU_LongName = 'L'};
 
    FileFd &File;
-   unsigned long MaxInSize;
+   unsigned long long MaxInSize;
    int GZPid;
    FileFd InFd;
    bool Eof;
@@ -53,7 +53,7 @@ class ExtractTar
 
    bool Go(pkgDirStream &Stream);
    
-   ExtractTar(FileFd &Fd,unsigned long Max,std::string DecompressionProgram);
+   ExtractTar(FileFd &Fd,unsigned long long Max,std::string DecompressionProgram);
    virtual ~ExtractTar();
 };
 
diff --git a/apt-inst/deb/debfile.cc b/apt-inst/deb/debfile.cc
index a63cb67..4853a13 100644
--- a/apt-inst/deb/debfile.cc
+++ b/apt-inst/deb/debfile.cc
@@ -203,7 +203,7 @@ bool debDebFile::MemControlExtract::DoItem(Item &Itm,int &Fd)
 /* Just memcopy the block from the tar extractor and put it in the right
    place in the pre-allocated memory block. */
 bool debDebFile::MemControlExtract::Process(Item &/*Itm*/,const unsigned char *Data,
-			     unsigned long Size,unsigned long Pos)
+			     unsigned long long Size,unsigned long long Pos)
 {
    memcpy(Control + Pos, Data,Size);
    return true;
@@ -232,7 +232,7 @@ bool debDebFile::MemControlExtract::Read(debDebFile &Deb)
 // ---------------------------------------------------------------------
 /* The given memory block is loaded into the parser and parsed as a control
    record. */
-bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long Size)
+bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long long Size)
 {
    delete [] Control;
    Control = new char[Size+2];
diff --git a/apt-inst/deb/debfile.h b/apt-inst/deb/debfile.h
index 880bcf6..b068efc 100644
--- a/apt-inst/deb/debfile.h
+++ b/apt-inst/deb/debfile.h
@@ -81,12 +81,12 @@ class debDebFile::MemControlExtract : public pkgDirStream
    // Members from DirStream
    virtual bool DoItem(Item &Itm,int &Fd);
    virtual bool Process(Item &Itm,const unsigned char *Data,
-			unsigned long Size,unsigned long Pos);
+			unsigned long long Size,unsigned long long Pos);
    
 
    // Helpers
    bool Read(debDebFile &Deb);
-   bool TakeControl(const void *Data,unsigned long Size);
+   bool TakeControl(const void *Data,unsigned long long Size);
       
    MemControlExtract() : IsControl(false), Control(0), Length(0), Member("control") {};
    MemControlExtract(std::string Member) : IsControl(false), Control(0), Length(0), Member(Member) {};
diff --git a/apt-inst/dirstream.h b/apt-inst/dirstream.h
index 1be2688..571fe86 100644
--- a/apt-inst/dirstream.h
+++ b/apt-inst/dirstream.h
@@ -37,10 +37,10 @@ class pkgDirStream
 	           Directory, FIFO} Type;
       char *Name;
       char *LinkTarget;
+      unsigned long long Size;
       unsigned long Mode;
       unsigned long UID;
       unsigned long GID;
-      unsigned long Size;
       unsigned long MTime;
       unsigned long Major;
       unsigned long Minor;
@@ -50,7 +50,7 @@ class pkgDirStream
    virtual bool Fail(Item &Itm,int Fd);
    virtual bool FinishedFile(Item &Itm,int Fd);
    virtual bool Process(Item &/*Itm*/,const unsigned char * /*Data*/,
-			unsigned long /*Size*/,unsigned long /*Pos*/) {return true;};
+			unsigned long long /*Size*/,unsigned long long /*Pos*/) {return true;};
       
    virtual ~pkgDirStream() {};   
 };
diff --git a/cmdline/apt-extracttemplates.cc b/cmdline/apt-extracttemplates.cc
index e4428e0..e2d0c0d 100644
--- a/cmdline/apt-extracttemplates.cc
+++ b/cmdline/apt-extracttemplates.cc
@@ -138,7 +138,7 @@ bool DebFile::DoItem(Item &I, int &Fd)
 // ---------------------------------------------------------------------
 /* */
 bool DebFile::Process(Item &/*I*/, const unsigned char *data,
-		unsigned long size, unsigned long pos)
+		unsigned long long size, unsigned long long pos)
 {
 	switch (Which)
 	{
diff --git a/cmdline/apt-extracttemplates.h b/cmdline/apt-extracttemplates.h
index 9cc3f5f..27137df 100644
--- a/cmdline/apt-extracttemplates.h
+++ b/cmdline/apt-extracttemplates.h
@@ -20,7 +20,7 @@ class pkgCache;
 class DebFile : public pkgDirStream
 {
 	FileFd File;
-	unsigned long Size;
+	unsigned long long Size;
 	char *Control;
 	unsigned long ControlLen;
 	
@@ -29,7 +29,7 @@ public:
 	~DebFile();
 	bool DoItem(Item &I, int &fd);
 	bool Process(pkgDirStream::Item &I, const unsigned char *data, 
-		unsigned long size, unsigned long pos);
+		unsigned long long size, unsigned long long pos);
 
 	bool Go();
 	bool ParseInfo();
diff --git a/debian/libapt-inst1.5.symbols b/debian/libapt-inst1.5.symbols
index 8ce7072..c5ab7f4 100644
--- a/debian/libapt-inst1.5.symbols
+++ b/debian/libapt-inst1.5.symbols
@@ -3,7 +3,7 @@ libapt-inst.so.1.5 libapt-inst1.5 #MINVER#
  (c++)"ExtractTar::Done(bool)@Base" 0.8.0
  (c++)"ExtractTar::Go(pkgDirStream&)@Base" 0.8.0
  (c++)"ExtractTar::StartGzip()@Base" 0.8.0
- (c++)"ExtractTar::ExtractTar(FileFd&, unsigned long, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 0.8.0
+ (c++)"ExtractTar::ExtractTar(FileFd&, unsigned long long, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 1.0.5
  (c++)"ExtractTar::~ExtractTar()@Base" 0.8.0
  (c++)"debDebFile::GotoMember(char const*)@Base" 0.8.0
  (c++)"debDebFile::CheckMember(char const*)@Base" 0.8.0
@@ -11,10 +11,10 @@ libapt-inst.so.1.5 libapt-inst1.5 #MINVER#
  (c++)"debDebFile::ControlExtract::~ControlExtract()@Base" 0.8.0
  (c++)"debDebFile::ExtractTarMember(pkgDirStream&, char const*)@Base" 0.9.15.4
  (c++)"debDebFile::ExtractArchive(pkgDirStream&)@Base" 0.8.0
- (c++)"debDebFile::MemControlExtract::TakeControl(void const*, unsigned long)@Base" 0.8.0
+ (c++)"debDebFile::MemControlExtract::TakeControl(void const*, unsigned long long)@Base" 1.0.5
  (c++)"debDebFile::MemControlExtract::Read(debDebFile&)@Base" 0.8.0
  (c++)"debDebFile::MemControlExtract::DoItem(pkgDirStream::Item&, int&)@Base" 0.8.0
- (c++)"debDebFile::MemControlExtract::Process(pkgDirStream::Item&, unsigned char const*, unsigned long, unsigned long)@Base" 0.8.0
+ (c++)"debDebFile::MemControlExtract::Process(pkgDirStream::Item&, unsigned char const*, unsigned long long, unsigned long long)@Base" 1.0.5
  (c++)"debDebFile::MemControlExtract::~MemControlExtract()@Base" 0.8.0
  (c++)"debDebFile::debDebFile(FileFd&)@Base" 0.8.0
  (c++)"pkgExtract::FinishedFile(pkgDirStream::Item&, int)@Base" 0.8.0
@@ -41,7 +41,7 @@ libapt-inst.so.1.5 libapt-inst1.5 #MINVER#
  (c++)"pkgDirStream::FinishedFile(pkgDirStream::Item&, int)@Base" 0.8.0
  (c++)"pkgDirStream::Fail(pkgDirStream::Item&, int)@Base" 0.8.0
  (c++)"pkgDirStream::DoItem(pkgDirStream::Item&, int&)@Base" 0.8.0
- (c++)"pkgDirStream::Process(pkgDirStream::Item&, unsigned char const*, unsigned long, unsigned long)@Base" 0.8.0
+ (c++)"pkgDirStream::Process(pkgDirStream::Item&, unsigned char const*, unsigned long long, unsigned long long)@Base" 1.0.5
  (c++)"pkgDirStream::~pkgDirStream()@Base" 0.8.0
  (c++|optional)"pkgCache::DepIterator::operator++(int)@Base" 0.8.0
  (c++|optional)"pkgCache::DepIterator::operator++()@Base" 0.8.0
-- 
2.0.1


Reply to: