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

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.
Julian Andres Klode лет назад: 11
Родитель
Сommit
1c73b0fc41

+ 11 - 0
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)

+ 2 - 0
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();
 };

+ 6 - 1
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;

+ 7 - 0
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

+ 30 - 0
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