summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2015-08-21 18:00:37 +0200
committerJulian Andres Klode <jak@debian.org>2015-08-27 14:51:47 +0200
commit1c73b0fc41c23a08994ef1464c529e0aacff16de (patch)
tree1cbbd50cdf9849b96081a38375f6014f4701cdae
parentf19d6a77f60b876e5453614d24886aabdd242ef6 (diff)
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.
-rw-r--r--apt-pkg/deb/debindexfile.cc11
-rw-r--r--apt-pkg/deb/debindexfile.h2
-rw-r--r--apt-pkg/deb/deblistparser.cc7
-rw-r--r--apt-pkg/deb/deblistparser.h7
-rwxr-xr-xtest/integration/test-security-no-remote-status30
5 files changed, 56 insertions, 1 deletions
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
@@ -374,6 +374,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;
if (Section.Find("Status",Start,Stop) == false)
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