From 8083d4019844f764058efa2a950ed16975178bff Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Thu, 10 Jun 2021 18:06:14 +0200 Subject: Restore dpkg::chroot-directory functionality If we call dpkg inside a chroot we have to ensure that the temporary directory we construct to call dpkg --recursive is inside the chroot and that we strip the path to the chroot from the directory name we pass to dpkg. Note that the added test succeeds before and (hopefully) after as we can't really chroot here or fiddle with the needed settings as we are already setting up apt to work with a quasi-chroot. The test perhaps helps in ensuring we don't break it too much in the future though. (Broken five years (and one day) ago this seems to have an immense user base at the moment, but it might in the future via mmdebstrap) References: f495992428a396e0f98886c9a761a804aa161c68 Reported-By: Johannes Schauer Marin Rodrigues on IRC Tested-By: Johannes Schauer Marin Rodrigues --- apt-pkg/deb/debsystem.cc | 25 ++++++++++++++----------- apt-pkg/deb/debsystem.h | 1 + apt-pkg/deb/dpkgpm.cc | 30 +++++++++++------------------- test/integration/test-apt-get-install-deb | 8 ++++++++ 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/apt-pkg/deb/debsystem.cc b/apt-pkg/deb/debsystem.cc index a0200305d..c9c6a7e85 100644 --- a/apt-pkg/deb/debsystem.cc +++ b/apt-pkg/deb/debsystem.cc @@ -358,19 +358,22 @@ bool debSystem::FindIndex(pkgCache::PkgFileIterator File, return false; } /*}}}*/ - +std::string debSystem::StripDpkgChrootDirectory(std::string const &File)/*{{{*/ +{ + // If the filename string begins with DPkg::Chroot-Directory, return the + // substr that is within the chroot so dpkg can access it. + std::string const chrootdir = _config->FindDir("DPkg::Chroot-Directory","/"); + size_t len = chrootdir.length(); + if (chrootdir == "/" || File.compare(0, len, chrootdir) != 0) + return File; + if (chrootdir.at(len - 1) == '/') + --len; + return File.substr(len); +} + /*}}}*/ std::string debSystem::GetDpkgExecutable() /*{{{*/ { - string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); - string const dpkgChrootDir = _config->FindDir("DPkg::Chroot-Directory", "/"); - size_t dpkgChrootLen = dpkgChrootDir.length(); - if (dpkgChrootDir != "/" && Tmp.find(dpkgChrootDir) == 0) - { - if (dpkgChrootDir[dpkgChrootLen - 1] == '/') - --dpkgChrootLen; - Tmp = Tmp.substr(dpkgChrootLen); - } - return Tmp; + return StripDpkgChrootDirectory(_config->Find("Dir::Bin::dpkg","dpkg")); } /*}}}*/ std::vector debSystem::GetDpkgBaseCommand() /*{{{*/ diff --git a/apt-pkg/deb/debsystem.h b/apt-pkg/deb/debsystem.h index b3d241512..c426faf81 100644 --- a/apt-pkg/deb/debsystem.h +++ b/apt-pkg/deb/debsystem.h @@ -43,6 +43,7 @@ class debSystem : public pkgSystem APT_HIDDEN static std::string GetDpkgExecutable(); APT_HIDDEN static std::vector GetDpkgBaseCommand(); APT_HIDDEN static void DpkgChrootDirectory(); + APT_HIDDEN static std::string StripDpkgChrootDirectory(std::string const &File); APT_HIDDEN static pid_t ExecDpkg(std::vector const &sArgs, int * const inputFd, int * const outputFd, bool const DiscardOutput); bool MultiArchSupported() const override; static bool AssertFeature(std::string const &Feature); diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index c1a9f6f68..09d605feb 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -248,19 +248,7 @@ bool pkgDPkgPM::Install(PkgIterator Pkg,string File) if (File.empty() == true || Pkg.end() == true) return _error->Error("Internal Error, No file name for %s",Pkg.FullName().c_str()); - // If the filename string begins with DPkg::Chroot-Directory, return the - // substr that is within the chroot so dpkg can access it. - string const chrootdir = _config->FindDir("DPkg::Chroot-Directory","/"); - if (chrootdir != "/" && File.find(chrootdir) == 0) - { - size_t len = chrootdir.length(); - if (chrootdir.at(len - 1) == '/') - len--; - List.push_back(Item(Item::Install,Pkg,File.substr(len))); - } - else - List.push_back(Item(Item::Install,Pkg,File)); - + List.emplace_back(Item::Install, Pkg, debSystem::StripDpkgChrootDirectory(File)); return true; } /*}}}*/ @@ -1855,6 +1843,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) } std::unique_ptr tmpdir_for_dpkg_recursive{nullptr, &cleanUpTmpDir}; + std::string const dpkg_chroot_dir = _config->FindDir("DPkg::Chroot-Directory", "/"); // Write in the file or package names if (I->Op == Item::Install) @@ -1862,11 +1851,14 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) auto const installsToDo = J - I; if (dpkg_recursive_install == true && dpkg_recursive_install_min < installsToDo) { - std::string tmpdir; - strprintf(tmpdir, "%s/apt-dpkg-install-XXXXXX", GetTempDir().c_str()); - tmpdir_for_dpkg_recursive.reset(strndup(tmpdir.data(), tmpdir.length())); - if (mkdtemp(tmpdir_for_dpkg_recursive.get()) == nullptr) - return _error->Errno("DPkg::Go", "mkdtemp of %s failed in preparation of calling dpkg unpack", tmpdir_for_dpkg_recursive.get()); + { + std::string basetmpdir = (dpkg_chroot_dir == "/") ? GetTempDir() : flCombine(dpkg_chroot_dir, "tmp"); + std::string tmpdir; + strprintf(tmpdir, "%s/apt-dpkg-install-XXXXXX", basetmpdir.c_str()); + tmpdir_for_dpkg_recursive.reset(strndup(tmpdir.data(), tmpdir.length())); + if (mkdtemp(tmpdir_for_dpkg_recursive.get()) == nullptr) + return _error->Errno("DPkg::Go", "mkdtemp of %s failed in preparation of calling dpkg unpack", tmpdir_for_dpkg_recursive.get()); + } char p = 1; for (auto c = installsToDo - 1; (c = c/10) != 0; ++p); @@ -1886,7 +1878,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) return _error->Errno("DPkg::Go", "Symlinking %s to %s failed!", I->File.c_str(), linkpath.c_str()); } Args.push_back("--recursive"); - Args.push_back(tmpdir_for_dpkg_recursive.get()); + Args.push_back(debSystem::StripDpkgChrootDirectory(tmpdir_for_dpkg_recursive.get())); } else { diff --git a/test/integration/test-apt-get-install-deb b/test/integration/test-apt-get-install-deb index 3d0b9a80d..bcf8bae3d 100755 --- a/test/integration/test-apt-get-install-deb +++ b/test/integration/test-apt-get-install-deb @@ -228,6 +228,14 @@ echo 'dpkg::install::recursive "true"; dpkg::install::recursive::force "true"; dpkg::install::recursive::minimum "0";' > rootdir/etc/apt/apt.conf.d/lowerminimum.conf mv ./incoming/pkg-as-it-should-be_0_all.deb ./incoming/pkg-as-it-should-be_0%3a0+0_all.ddeb +testsuccess aptget install -y ./incoming/pkg-as-it-should-be_0%3a0+0_all.ddeb --reinstall -o Debug::pkgDpkgPm=1 +cp rootdir/tmp/testsuccess.output apt.output +testsuccess grep "^${TMPWORKINGDIRECTORY}/.*/dpkg.* --recursive .*/apt-dpkg-install-" apt.output +testsuccess aptget install -y ./incoming/pkg-as-it-should-be_0%3a0+0_all.ddeb --reinstall -o Debug::pkgDpkgPm=1 -o DPkg::Chroot-Directory="${TMPWORKINGDIRECTORY}/rootdir/" +cp rootdir/tmp/testsuccess.output apt.output +testsuccess grep 'dpkg.* --recursive .*/apt-dpkg-install-' apt.output +testfailure grep "^${TMPWORKINGDIRECTORY}/.*/dpkg.* --recursive .*/apt-dpkg-install-" apt.output +testfailure grep "dpkg.* --recursive ${TMPWORKINGDIRECTORY}" apt.output testsuccess aptget install -y ./incoming/pkg-as-it-should-be_0%3a0+0_all.ddeb --reinstall testfailure grep 'is already the newest version' rootdir/tmp/testsuccess.output testsuccess apt purge -y pkg-as-it-should-be -- cgit v1.2.3-70-g09d2