Просмотр исходного кода

do not segfault in cache generation on mmap failure

Out of memory and similar circumstanzas could cause MMap::Map to fail
and especially the mmap/malloc calls in it. With some additional
checking we can avoid segfaults and similar in such situations – at
least in theory as if this is a real out of memory everything we do to
handle the error could just as well run into a memory problem as well…

But at least in theory (if MMap::Map is made to fail always) we can deal
with it so good that a user actually never sees a failure (as the cache
it tries to load with it fails and is discarded, so that DynamicMMap
takes over and a new one is build) instead of segfaulting.

Closes: 803417
David Kalnischkies лет назад: 10
Родитель
Сommit
6789e01e93
3 измененных файлов с 21 добавлено и 6 удалено
  1. 2 0
      apt-pkg/cachefile.cc
  2. 10 5
      apt-pkg/contrib/mmap.cc
  3. 9 1
      apt-pkg/pkgcachegen.cc

+ 2 - 0
apt-pkg/cachefile.cc

@@ -80,6 +80,8 @@ bool pkgCacheFile::BuildCaches(OpProgress *Progress, bool WithLock)
       if (file.IsOpen() == false || file.Failed())
 	 return false;
       Map = new MMap(file, MMap::Public|MMap::ReadOnly);
+      if (unlikely(Map->validData() == false))
+	 return false;
       Cache = new pkgCache(Map);
       return _error->PendingError() == false;
    }

+ 10 - 5
apt-pkg/contrib/mmap.cc

@@ -38,7 +38,7 @@
 // ---------------------------------------------------------------------
 /* */
 MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
-                     Base(0), SyncToFd(NULL)
+                     Base(nullptr), SyncToFd(nullptr)
 {
    if ((Flags & NoImmMap) != NoImmMap)
       Map(F);
@@ -48,7 +48,7 @@ MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
 // ---------------------------------------------------------------------
 /* */
 MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
-                     Base(0), SyncToFd(NULL)
+                     Base(nullptr), SyncToFd(nullptr)
 {
 }
 									/*}}}*/
@@ -84,6 +84,8 @@ bool MMap::Map(FileFd &Fd)
       if ((Flags & ReadOnly) != ReadOnly)
 	 return _error->Error("Compressed file %s can only be mapped readonly", Fd.Name().c_str());
       Base = malloc(iSize);
+      if (unlikely(Base == nullptr))
+	 return _error->Errno("MMap-compressed-malloc", _("Couldn't make mmap of %llu bytes"), iSize);
       SyncToFd = new FileFd();
       if (Fd.Seek(0L) == false || Fd.Read(Base, iSize) == false)
 	 return _error->Error("Compressed file %s can't be read into mmap", Fd.Name().c_str());
@@ -92,7 +94,7 @@ bool MMap::Map(FileFd &Fd)
 
    // Map it.
    Base = (Flags & Fallback) ? MAP_FAILED : mmap(0,iSize,Prot,Map,Fd.Fd(),0);
-   if (Base == (void *)-1)
+   if (Base == MAP_FAILED)
    {
       if (errno == ENODEV || errno == EINVAL || (Flags & Fallback))
       {
@@ -102,6 +104,8 @@ bool MMap::Map(FileFd &Fd)
 	 {
 	    // for readonly, we don't need sync, so make it simple
 	    Base = malloc(iSize);
+	    if (unlikely(Base == nullptr))
+	       return _error->Errno("MMap-malloc", _("Couldn't make mmap of %llu bytes"), iSize);
 	    SyncToFd = new FileFd();
 	    return Fd.Read(Base, iSize);
 	 }
@@ -111,13 +115,14 @@ bool MMap::Map(FileFd &Fd)
 	    return _error->Errno("mmap", _("Couldn't duplicate file descriptor %i"), Fd.Fd());
 
 	 Base = calloc(iSize, 1);
+	 if (unlikely(Base == nullptr))
+	    return _error->Errno("MMap-calloc", _("Couldn't make mmap of %llu bytes"), iSize);
 	 SyncToFd = new FileFd (dupped_fd);
 	 if (!SyncToFd->Seek(0L) || !SyncToFd->Read(Base, iSize))
 	    return false;
       }
       else
-	 return _error->Errno("mmap",_("Couldn't make mmap of %llu bytes"),
-	                      iSize);
+	 return _error->Errno("MMap-mmap", _("Couldn't make mmap of %llu bytes"), iSize);
      }
 
    return true;

+ 9 - 1
apt-pkg/pkgcachegen.cc

@@ -125,7 +125,7 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
    advoid a problem during a crash */
 pkgCacheGenerator::~pkgCacheGenerator()
 {
-   if (_error->PendingError() == true)
+   if (_error->PendingError() == true || Map.validData() == false)
       return;
    if (Map.Sync() == false)
       return;
@@ -1307,6 +1307,8 @@ static bool CheckValidity(const string &CacheFile,
    // Map it
    FileFd CacheF(CacheFile,FileFd::ReadOnly);
    std::unique_ptr<MMap> Map(new MMap(CacheF,0));
+   if (unlikely(Map->validData()) == false)
+      return false;
    pkgCache Cache(Map.get());
    if (_error->PendingError() || Map->Size() == 0)
    {
@@ -1539,6 +1541,8 @@ static bool loadBackMMapFromFile(std::unique_ptr<pkgCacheGenerator> &Gen,
       std::unique_ptr<DynamicMMap> &Map, OpProgress * const Progress, std::string const &FileName)
 {
    Map.reset(CreateDynamicMMap(NULL, 0));
+   if (unlikely(Map->validData()) == false)
+      return false;
    FileFd CacheF(FileName, FileFd::ReadOnly);
    if (CacheF.IsOpen() == false || CacheF.Failed())
       return false;
@@ -1628,6 +1632,8 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
 
    // At this point we know we need to construct something, so get storage ready
    std::unique_ptr<DynamicMMap> Map(CreateDynamicMMap(NULL, 0));
+   if (unlikely(Map->validData()) == false)
+      return false;
    if (Debug == true)
       std::clog << "Open memory Map (not filebased)" << std::endl;
 
@@ -1716,6 +1722,8 @@ bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **O
 
    ScopedErrorMerge sem;
    std::unique_ptr<DynamicMMap> Map(CreateDynamicMMap(NULL, 0));
+   if (unlikely(Map->validData()) == false)
+      return false;
    map_filesize_t CurrentSize = 0;
    map_filesize_t TotalSize = 0;
    TotalSize = ComputeSize(NULL, Files.begin(), Files.end());