From 1c73b0fc41c23a08994ef1464c529e0aacff16de Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 21 Aug 2015 18:00:37 +0200 Subject: Do not parse Status fields from remote sources This could allow an attacker to mark a package as installed in a remote package index, as long as the package was not listed in the dpkg status file. This way, an attacker could force the installation of a package during a dist-upgrade, by providing two packages in an index, an older marked as installed, and a newer - apt would "upgrade" to the newer version. --- apt-pkg/deb/debindexfile.cc | 11 +++++++++ apt-pkg/deb/debindexfile.h | 2 ++ apt-pkg/deb/deblistparser.cc | 7 +++++- apt-pkg/deb/deblistparser.h | 7 ++++++ test/integration/test-security-no-remote-status | 30 +++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100755 test/integration/test-security-no-remote-status diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc index c43ee7b91..32ccd7529 100644 --- a/apt-pkg/deb/debindexfile.cc +++ b/apt-pkg/deb/debindexfile.cc @@ -145,6 +145,17 @@ uint8_t debStatusIndex::GetIndexFlags() const { return pkgCache::Flag::NotSource; } + +pkgCacheListParser * debStatusIndex::CreateListParser(FileFd &Pkg) +{ + if (Pkg.IsOpen() == false) + return NULL; + _error->PushToStack(); + pkgCacheListParser * const Parser = new debStatusListParser(&Pkg); + bool const newError = _error->PendingError(); + _error->MergeWithStack(); + return newError ? NULL : Parser; +} /*}}}*/ // DebPkgFile Index - a single .deb file as an index /*{{{*/ debDebPkgFileIndex::debDebPkgFileIndex(std::string const &DebFile) diff --git a/apt-pkg/deb/debindexfile.h b/apt-pkg/deb/debindexfile.h index dc75a01ab..5bec4f2ea 100644 --- a/apt-pkg/deb/debindexfile.h +++ b/apt-pkg/deb/debindexfile.h @@ -43,6 +43,8 @@ public: // Abort if the file does not exist. virtual bool Exists() const APT_OVERRIDE {return true;}; + virtual pkgCacheListParser * CreateListParser(FileFd &Pkg) APT_OVERRIDE; + debStatusIndex(std::string const &File); virtual ~debStatusIndex(); }; diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 42eca8677..d88e25e6f 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -362,7 +362,7 @@ unsigned short debListParser::VersionHash() return Result; } /*}}}*/ -// ListParser::ParseStatus - Parse the status field /*{{{*/ +// StatusListParser::ParseStatus - Parse the status field /*{{{*/ // --------------------------------------------------------------------- /* Status lines are of the form, Status: want flag status @@ -373,6 +373,11 @@ unsigned short debListParser::VersionHash() */ bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver) +{ + return true; +} +bool debStatusListParser::ParseStatus(pkgCache::PkgIterator &Pkg, + pkgCache::VerIterator &Ver) { const char *Start; const char *Stop; diff --git a/apt-pkg/deb/deblistparser.h b/apt-pkg/deb/deblistparser.h index 747e022d8..0884479db 100644 --- a/apt-pkg/deb/deblistparser.h +++ b/apt-pkg/deb/deblistparser.h @@ -119,4 +119,11 @@ class APT_HIDDEN debTranslationsParser : public debListParser : debListParser(File) {}; }; +class APT_HIDDEN debStatusListParser : public debListParser +{ + public: + virtual bool ParseStatus(pkgCache::PkgIterator &Pkg,pkgCache::VerIterator &Ver); + debStatusListParser(FileFd *File) + : debListParser(File) {}; +}; #endif diff --git a/test/integration/test-security-no-remote-status b/test/integration/test-security-no-remote-status new file mode 100755 index 000000000..b7cd0b0d1 --- /dev/null +++ b/test/integration/test-security-no-remote-status @@ -0,0 +1,30 @@ +#!/bin/sh +# +# Test that packages from remote sources cannot set the Status field. +# +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework +setupenvironment +configarchitecture 'amd64' + +TMPDIR=$(readlink -f .) + +insertpackage 'unstable' 'pretends-installed' 'all' '1' 'Status: install ok installed' +insertinstalledpackage 'really-installed' 'all' '1' +setupaptarchive + +testequal "pretends-installed: + Installed: (none) + Candidate: 1 + Version table: + 1 0 + 500 file:${TMPDIR}/aptarchive/ unstable/main amd64 Packages" aptcache policy pretends-installed + +testequal "really-installed: + Installed: 1 + Candidate: 1 + Version table: + *** 1 0 + 100 ${TMPDIR}/rootdir/var/lib/dpkg/status" aptcache policy really-installed -- cgit v1.2.3