From 22e3f5d3e311bc001a05803fcf39036f620b1d96 Mon Sep 17 00:00:00 2001 From: "Heitor R. Alves de Siqueira" Date: Fri, 8 Feb 2019 13:05:18 +0100 Subject: backport "do not segfault in cache generation on mmap failure" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message: 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 LP: #1815129 --- apt-pkg/cachefile.cc | 2 ++ apt-pkg/contrib/mmap.cc | 11 ++++++++--- apt-pkg/pkgcachegen.cc | 10 ++++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apt-pkg/cachefile.cc b/apt-pkg/cachefile.cc index 96bcdc097..622d38367 100644 --- a/apt-pkg/cachefile.cc +++ b/apt-pkg/cachefile.cc @@ -67,6 +67,8 @@ bool pkgCacheFile::BuildCaches(OpProgress *Progress, bool WithLock) { Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"), FileFd::ReadOnly),MMap::Public|MMap::ReadOnly); + if (unlikely(Map->validData() == false)) + return false; Cache = new pkgCache(Map); if (_error->PendingError() == true) return false; diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc index b2a53a6cb..f82537afb 100644 --- a/apt-pkg/contrib/mmap.cc +++ b/apt-pkg/contrib/mmap.cc @@ -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 == NULL)) + 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 == NULL)) + 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 == NULL)) + 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; diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 810f0b022..11e529d41 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -59,7 +59,7 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : CurrentFile = 0; memset(UniqHash,0,sizeof(UniqHash)); - if (_error->PendingError() == true) + if (_error->PendingError() == true || Map.validData() == false) return; if (Map.Size() == 0) @@ -1181,6 +1181,8 @@ static bool CheckValidity(const string &CacheFile, // Map it FileFd CacheF(CacheFile,FileFd::ReadOnly); SPtr Map = new MMap(CacheF,0); + if (unlikely(Map->validData() == false)) + return false; pkgCache Cache(Map); if (_error->PendingError() == true || Map->Size() == 0) { @@ -1425,7 +1427,7 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress CacheF = new FileFd(CacheFile,FileFd::WriteAtomic); fchmod(CacheF->Fd(),0644); Map = CreateDynamicMMap(CacheF, MMap::Public); - if (_error->PendingError() == true) + if (_error->PendingError() == true || Map->validData() == false) { delete CacheF.UnGuard(); delete Map.UnGuard(); @@ -1450,6 +1452,8 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress { // Just build it in memory.. Map = CreateDynamicMMap(NULL); + if (unlikely(Map->validData() == false)) + return false; if (Debug == true) std::clog << "Open memory Map (not filebased)" << std::endl; } @@ -1556,6 +1560,8 @@ bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **O return false; SPtr Map = CreateDynamicMMap(NULL); + if (unlikely(Map->validData() == false)) + return false; unsigned long CurrentSize = 0; unsigned long TotalSize = 0; -- cgit v1.2.3