From 859093dae7dcadaff2e15a3885a1824b0d5f5913 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 30 Aug 2014 11:29:45 +0200 Subject: support regular expressions in 'apt search' apt-cache search supported this since ever and in the code for apt was a fixme indicating this should be added here as well, so here we go. --- test/integration/framework | 8 +++++++- test/integration/test-apt-cli-search | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/integration/framework b/test/integration/framework index 3bbf440c8..fde74f55d 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -1019,7 +1019,13 @@ testfileequal() { testempty() { msgtest "Test for no output of" "$*" - test -z "$($* 2>&1)" && msgpass || msgfail + local COMPAREFILE="${TMPWORKINGDIRECTORY}/rootdir/tmp/testempty.comparefile" + if $* >$COMPAREFILE 2>&1 && test ! -s $COMPAREFILE; then + msgpass + else + cat $COMPAREFILE + msgfail + fi } testequal() { diff --git a/test/integration/test-apt-cli-search b/test/integration/test-apt-cli-search index 58613717b..3ac074952 100755 --- a/test/integration/test-apt-cli-search +++ b/test/integration/test-apt-cli-search @@ -33,16 +33,31 @@ foo/unstable 1.0 all testequal "foo/unstable 1.0 all $DESCR " apt search -qq xxyyzz +testempty apt search -qq --names-only xxyyzz + +# search name +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq foo +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq --names-only foo # search with multiple words is a AND search testequal "foo/unstable 1.0 all $DESCR " apt search -qq aabbcc xxyyzz +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq 'a+b+c+' 'i*xxy{0,2}zz' # search is not case-sensitive by default testequal "foo/unstable 1.0 all $DESCR " apt search -qq uppercase +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq 'up[pP]erc[Aa]se' # output is sorted and search word finds both package testequal "bar/testing 2.0 i386 -- cgit v1.2.3-70-g09d2 From 1a68655de92fd036ebc7c920bc2e5e88c54eb34e Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Tue, 2 Sep 2014 14:32:48 +0200 Subject: implement --full in apt search --- apt-private/private-list.cc | 39 ++++++++++++++----------------- apt-private/private-output.cc | 45 +++++++++++++++++++++++++----------- apt-private/private-output.h | 4 ++-- apt-private/private-search.cc | 9 +++++++- test/integration/test-apt-cli-search | 16 ++++++++++++- 5 files changed, 73 insertions(+), 40 deletions(-) (limited to 'test') diff --git a/apt-private/private-list.cc b/apt-private/private-list.cc index b69002103..d746acf3f 100644 --- a/apt-private/private-list.cc +++ b/apt-private/private-list.cc @@ -85,15 +85,14 @@ private: }; /*}}}*/ static void ListAllVersions(pkgCacheFile &CacheFile, pkgRecords &records,/*{{{*/ - pkgCache::PkgIterator P, - std::ostream &outs, - bool include_summary=true) + pkgCache::PkgIterator const &P, std::ostream &outs, + std::string const &format) { for (pkgCache::VerIterator Ver = P.VersionList(); Ver.end() == false; ++Ver) { - ListSingleVersion(CacheFile, records, Ver, outs, include_summary); - outs << "\n"; + ListSingleVersion(CacheFile, records, Ver, outs, format); + outs << std::endl; } } /*}}}*/ @@ -117,10 +116,9 @@ bool DoList(CommandLine &Cmd) patterns = Cmd.FileList + 1; } - std::map output_map; - std::map::const_iterator K; - - bool includeSummary = _config->FindB("APT::Cmd::List-Include-Summary"); + std::string format = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture}${ }${apt:Status}"; + if (_config->FindB("APT::Cmd::List-Include-Summary", false) == true) + format += "\n ${Description}\n"; PackageNameMatcher matcher(patterns); LocalitySortedVersionSet bag; @@ -130,36 +128,33 @@ bool DoList(CommandLine &Cmd) Cache->Head().PackageCount, _("Listing")); GetLocalitySortedVersionSet(CacheFile, bag, matcher, progress); - bool ShowAllVersions = _config->FindB("APT::Cmd::All-Versions", false); + bool const ShowAllVersions = _config->FindB("APT::Cmd::All-Versions", false); + std::map output_map; for (LocalitySortedVersionSet::iterator V = bag.begin(); V != bag.end(); ++V) { std::stringstream outs; if(ShowAllVersions == true) - { - ListAllVersions(CacheFile, records, V.ParentPkg(), outs, includeSummary); - output_map.insert(std::make_pair( - V.ParentPkg().Name(), outs.str())); - } else { - ListSingleVersion(CacheFile, records, V, outs, includeSummary); - output_map.insert(std::make_pair( - V.ParentPkg().Name(), outs.str())); - } + ListAllVersions(CacheFile, records, V.ParentPkg(), outs, format); + else + ListSingleVersion(CacheFile, records, V, outs, format); + output_map.insert(std::make_pair( + V.ParentPkg().Name(), outs.str())); } // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status) // output the sorted map + std::map::const_iterator K; for (K = output_map.begin(); K != output_map.end(); ++K) std::cout << (*K).second << std::endl; - // be nice and tell the user if there is more to see if (bag.size() == 1 && ShowAllVersions == false) { // start with -1 as we already displayed one version int versions = -1; pkgCache::VerIterator Ver = *bag.begin(); - for ( ; Ver.end() == false; Ver++) - versions++; + for ( ; Ver.end() == false; ++Ver) + ++versions; if (versions > 0) _error->Notice(P_("There is %i additional version. Please use the '-a' switch to see it", "There are %i additional versions. Please use the '-a' switch to see them.", versions), versions); } diff --git a/apt-private/private-output.cc b/apt-private/private-output.cc index 7be56de2e..fc76a05bc 100644 --- a/apt-private/private-output.cc +++ b/apt-private/private-output.cc @@ -207,9 +207,31 @@ static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &reco return ShortDescription; } /*}}}*/ +static std::string GetLongDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/ +{ + pkgPolicy *policy = CacheFile.GetPolicy(); + + pkgCache::VerIterator ver; + if (P->CurrentVer != 0) + ver = P.CurrentVer(); + else + ver = policy->GetCandidateVer(P); + + std::string const EmptyDescription = "(none)"; + if(ver.end() == true) + return EmptyDescription; + + pkgCache::DescIterator const Desc = ver.TranslatedDescription(); + pkgRecords::Parser & parser = records.Lookup(Desc.FileList()); + std::string const longdesc = parser.LongDesc(); + if (longdesc.empty() == true) + return EmptyDescription; + return SubstVar(longdesc, "\n ", "\n "); +} + /*}}}*/ void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/ - pkgCache::VerIterator V, std::ostream &out, - bool include_summary) + pkgCache::VerIterator const &V, std::ostream &out, + std::string const &format) { pkgCache::PkgIterator const P = V.ParentPkg(); pkgDepCache * const DepCache = CacheFile.GetDepCache(); @@ -219,11 +241,7 @@ void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/ if (_config->FindB("APT::Cmd::use-format", false)) output = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}"); else - { - // linux-kernel/unstable version [installed,upradable to: new-version] - // description - output = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture} ${apt:Status}"; - } + output = format; // FIXME: some of these names are really icky – and all is nowhere documented output = SubstVar(output, "${db::Status-Abbrev}", GetFlagsStr(CacheFile, P)); @@ -264,14 +282,13 @@ void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/ output = SubstVar(output, "${apt:Status}", StatusStr); output = SubstVar(output, "${color:highlight}", _config->Find("APT::Color::Highlight", "")); output = SubstVar(output, "${color:neutral}", _config->Find("APT::Color::Neutral", "")); - - output = APT::String::Strip(output); - if (_config->FindB("APT::Cmd::use-format", false) == false) - { - if (include_summary) - output += "\n ${Description}\n"; - } output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P)); + output = SubstVar(output, "${LongDescription}", GetLongDescription(CacheFile, records, P)); + output = SubstVar(output, "${ }${ }", "${ }"); + output = SubstVar(output, "${ }\n", "\n"); + output = SubstVar(output, "${ }", " "); + if (APT::String::Endswith(output, " ") == true) + output.erase(output.length() - 1); out << output; } diff --git a/apt-private/private-output.h b/apt-private/private-output.h index 6f3a964d7..e0dc9bf62 100644 --- a/apt-private/private-output.h +++ b/apt-private/private-output.h @@ -23,8 +23,8 @@ APT_PUBLIC extern unsigned int ScreenWidth; APT_PUBLIC bool InitOutput(); void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, - pkgCache::VerIterator V, std::ostream &out, - bool include_summary=true); + pkgCache::VerIterator const &V, std::ostream &out, + std::string const &format); // helper to describe global state diff --git a/apt-private/private-search.cc b/apt-private/private-search.cc index 2d427fa25..5e12902e8 100644 --- a/apt-private/private-search.cc +++ b/apt-private/private-search.cc @@ -69,6 +69,13 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ progress.OverallProgress(50, 100, 50, _("Full Text Search")); progress.SubProgress(bag.size()); pkgRecords records(CacheFile); + + std::string format = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture}${ }${apt:Status}\n"; + if (_config->FindB("APT::Cache::ShowFull",false) == false) + format += " ${Description}\n"; + else + format += " ${LongDescription}\n"; + int Done = 0; for ( ;V != bag.end(); ++V) { @@ -100,7 +107,7 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ if (all_found == true) { std::stringstream outs; - ListSingleVersion(CacheFile, records, V, outs); + ListSingleVersion(CacheFile, records, V, outs, format); output_map.insert(std::make_pair( PkgName, outs.str())); } diff --git a/test/integration/test-apt-cli-search b/test/integration/test-apt-cli-search index 3ac074952..8f009d57c 100755 --- a/test/integration/test-apt-cli-search +++ b/test/integration/test-apt-cli-search @@ -15,7 +15,10 @@ fi DESCR='Some description that has a unusual word xxyyzz and aabbcc and a UPPERCASE' DESCR2='Some other description with the unusual aabbcc only' -insertpackage 'unstable' 'foo' 'all' '1.0' '' '' "$DESCR" +insertpackage 'unstable' 'foo' 'all' '1.0' '' '' "$DESCR + Long description of stuff and such, with lines + . + and paragraphs and everything." insertpackage 'testing' 'bar' 'i386' '2.0' '' '' "$DESCR2" setupaptarchive @@ -59,6 +62,17 @@ testequal "foo/unstable 1.0 all $DESCR " apt search -qq 'up[pP]erc[Aa]se' +# search is done in the long description +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq 'long description' +testequal "foo/unstable 1.0 all + $DESCR + Long description of stuff and such, with lines + . + and paragraphs and everything. +" apt search --full -qq 'long description' + # output is sorted and search word finds both package testequal "bar/testing 2.0 i386 $DESCR2 -- cgit v1.2.3-70-g09d2 From e9bb097c914ff4fb1cdeda8a2843644dca184c56 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 7 Sep 2014 19:28:21 +0200 Subject: do use an 'unknown' arch-specification in test Using 'kfreebsd' here makes the test fail on a kfreebsd system (obviously), so we just use something totally madeup in the hope that this is less like to conflict in the future. Git-Dch: Ignore --- test/integration/test-architecture-specification-parsing | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/integration/test-architecture-specification-parsing b/test/integration/test-architecture-specification-parsing index a43354871..d1f6011de 100755 --- a/test/integration/test-architecture-specification-parsing +++ b/test/integration/test-architecture-specification-parsing @@ -13,10 +13,10 @@ buildsimplenativepackage 'pkg-arch-foo' "$NATIVE" '1.0' 'stable' "Build-Depends: Depends: foo [${NATIVE} !${NATIVE}]" buildsimplenativepackage 'pkg-arch-no-foo' "$NATIVE" '1.0' 'stable' "Build-Depends: foo [!${NATIVE} ${NATIVE}] Depends: foo [!${NATIVE} ${NATIVE}]" -buildsimplenativepackage 'pkg-arch-foo-unrelated-no' "$NATIVE" '1.0' 'stable' "Build-Depends: foo [!kfreebsd-any ${NATIVE}] -Depends: foo [!kfreebsd-any ${NATIVE}]" -buildsimplenativepackage 'pkg-arch-foo-unrelated-no2' "$NATIVE" '1.0' 'stable' "Build-Depends: foo [${NATIVE} !kfreebsd-any] -Depends: foo [${NATIVE} !kfreebsd-any]" +buildsimplenativepackage 'pkg-arch-foo-unrelated-no' "$NATIVE" '1.0' 'stable' "Build-Depends: foo [!someos-any ${NATIVE}] +Depends: foo [!someos-any ${NATIVE}]" +buildsimplenativepackage 'pkg-arch-foo-unrelated-no2' "$NATIVE" '1.0' 'stable' "Build-Depends: foo [${NATIVE} !someos-any] +Depends: foo [${NATIVE} !someos-any]" buildsimplenativepackage 'no-depends' 'armel' '1.0' 'stable' 'Build-Depends: foo [armeb], bar [arm] Depends: foo [armeb], bar [arm]' -- cgit v1.2.3-70-g09d2 From 27cb4f6c919921b04f3dddff069620ced250a94f Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 7 Sep 2014 19:30:33 +0200 Subject: detect terminal output with 'test -t' in tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of trying to inspect /proc and the fds inside we use "test -t 1" instead as this is available and working on kfreebsd as well – not that something breaks if we wouldn't, but we like color. Git-Dch: Ignore --- test/integration/framework | 2 +- test/integration/run-tests | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/integration/framework b/test/integration/framework index fde74f55d..ff010a5c4 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -4,7 +4,7 @@ EXIT_CODE=0 # we all like colorful messages if [ "$MSGCOLOR" != 'NO' ]; then - if ! expr match "$(readlink -f /proc/$$/fd/1)" '/dev/pts/[0-9]\+' > /dev/null; then + if [ ! -t 1 ]; then # but check that we output to a terminal export MSGCOLOR='NO' fi fi diff --git a/test/integration/run-tests b/test/integration/run-tests index 9dd550aa2..c39a2ac68 100755 --- a/test/integration/run-tests +++ b/test/integration/run-tests @@ -22,7 +22,7 @@ done export MSGLEVEL="${MSGLEVEL:-3}" if [ "$MSGCOLOR" != 'NO' ]; then - if ! expr match "$(readlink -f /proc/$$/fd/1)" '/dev/pts/[0-9]\+' > /dev/null; then + if [ ! -t 1 ]; then # but check that we output to a terminal export MSGCOLOR='NO' fi fi -- cgit v1.2.3-70-g09d2 From b578738870e83db4e61d6f6591bc73884108b7d4 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 7 Sep 2014 21:27:57 +0200 Subject: strip everything spacey in APT::String::Strip Git-Dch: Ignore --- apt-pkg/contrib/strutl.cc | 24 ++++++++++++++++++------ test/libapt/strutil_test.cc | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 922229e90..87f57a30e 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -45,14 +45,26 @@ using namespace std; // --------------------------------------------------------------------- namespace APT { namespace String { -std::string Strip(const std::string &s) +std::string Strip(const std::string &str) { - size_t start = s.find_first_not_of(" \t\n"); - // only whitespace - if (start == string::npos) + // ensure we have at least one character + if (str.empty() == true) + return str; + + char const * const s = str.c_str(); + size_t start = 0; + for (; isspace(s[start]) != 0; ++start) + ; // find the first not-space + + // string contains only whitespaces + if (s[start] == '\0') return ""; - size_t end = s.find_last_not_of(" \t\n"); - return s.substr(start, end-start+1); + + size_t end = str.length() - 1; + for (; isspace(s[end]) != 0; --end) + ; // find the last not-space + + return str.substr(start, end - start + 1); } bool Endswith(const std::string &s, const std::string &end) diff --git a/test/libapt/strutil_test.cc b/test/libapt/strutil_test.cc index e9b778c6b..194c9c074 100644 --- a/test/libapt/strutil_test.cc +++ b/test/libapt/strutil_test.cc @@ -19,6 +19,21 @@ TEST(StrUtilTest,DeEscapeString) EXPECT_EQ("foo\\ x", DeEscapeString("foo\\\\ x")); EXPECT_EQ("\\foo\\", DeEscapeString("\\\\foo\\\\")); } +TEST(StrUtilTest,StringStrip) +{ + EXPECT_EQ("", APT::String::Strip("")); + EXPECT_EQ("foobar", APT::String::Strip("foobar")); + EXPECT_EQ("foo bar", APT::String::Strip("foo bar")); + + EXPECT_EQ("", APT::String::Strip(" ")); + EXPECT_EQ("", APT::String::Strip(" \r\n \t ")); + + EXPECT_EQ("foo bar", APT::String::Strip("foo bar ")); + EXPECT_EQ("foo bar", APT::String::Strip("foo bar \r\n \t ")); + EXPECT_EQ("foo bar", APT::String::Strip("\r\n \t foo bar")); + EXPECT_EQ("bar foo", APT::String::Strip("\r\n \t bar foo \r\n \t ")); + EXPECT_EQ("bar \t\r\n foo", APT::String::Strip("\r\n \t bar \t\r\n foo \r\n \t ")); +} TEST(StrUtilTest,StringSplitBasic) { std::vector result = StringSplit("", ""); -- cgit v1.2.3-70-g09d2 From f920cbe8527ce523974da2563ca1165790c1d40e Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 7 Sep 2014 22:08:01 +0200 Subject: fix and non-silent fail dpkg-overwrite error test Commit cbcdd3ee9d86379d1b3a44e41ae8b17dc23111d0 removes the space at the end of the debfile name dpkg send to us and we previously had included in the pmerror message we printed on the statusfd. Git-Dch: Ignore --- test/integration/test-apt-progress-fd-error | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/integration/test-apt-progress-fd-error b/test/integration/test-apt-progress-fd-error index 96d66371a..a47095b9b 100755 --- a/test/integration/test-apt-progress-fd-error +++ b/test/integration/test-apt-progress-fd-error @@ -18,5 +18,10 @@ setupaptarchive exec 3> apt-progress.log testfailure aptget install foo1 foo2 -y -o APT::Status-Fd=3 msgtest "Ensure correct error message" -grep -q "aptarchive/pool/foo2_0.8.15_amd64.deb :40:trying to overwrite '/usr/bin/file-conflict', which is also in package foo1 0.8.15" apt-progress.log && msgpass || (cat apt-progress.log && msgfail) +if grep -q "aptarchive/pool/foo2_0.8.15_amd64.deb:40:trying to overwrite '/usr/bin/file-conflict', which is also in package foo1 0.8.15" apt-progress.log; then + msgpass +else + cat apt-progress.log + msgfail +fi -- cgit v1.2.3-70-g09d2 From 4c559e97ba4cc0d3a2995b7c451e606539d2f1be Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 8 Sep 2014 17:14:17 +0200 Subject: fix progress report for upgrade and reinstall APT treats upgrades like installs and dpkg is very similar in this, but prints still a slightly different processing message indicating that it is really an upgrade which we hadn't parsed so far, but this wasn't really visible as we quickly moved on to a 'known' state. More problematic was the reinstall case as apt hadn't recognized this for the package name detection, so that reinstalls had no progress since we introduced MultiArch. --- apt-pkg/deb/dpkgpm.cc | 79 ++++++++++++++++++----------------- test/integration/test-apt-progress-fd | 16 +++++++ 2 files changed, 57 insertions(+), 38 deletions(-) (limited to 'test') diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 264304c61..5411d9ee8 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -564,8 +564,8 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line) 'status: : ' 'status: :: ' - 'processing: {install,configure,remove,purge,disappear,trigproc}: pkg' - 'processing: {install,configure,remove,purge,disappear,trigproc}: trigger' + 'processing: {install,upgrade,configure,remove,purge,disappear,trigproc}: pkg' + 'processing: {install,upgrade,configure,remove,purge,disappear,trigproc}: trigger' */ // we need to split on ": " (note the appended space) as the ':' is @@ -589,12 +589,15 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line) std::string action; // "processing" has the form "processing: action: pkg or trigger" - // with action = ["install", "configure", "remove", "purge", "disappear", - // "trigproc"] + // with action = ["install", "upgrade", "configure", "remove", "purge", + // "disappear", "trigproc"] if (prefix == "processing") { pkgname = APT::String::Strip(list[2]); action = APT::String::Strip(list[1]); + // we don't care for the difference (as dpkg doesn't really either) + if (action == "upgrade") + action = "install"; } // "status" has the form: "status: pkg: state" // with state in ["half-installed", "unpacked", "half-configured", @@ -638,27 +641,26 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line) // at this point we know that we should have a valid pkgname, so build all // the info from it - // dpkg does not send always send "pkgname:arch" so we add it here - // if needed + // dpkg does not always send "pkgname:arch" so we add it here if needed if (pkgname.find(":") == std::string::npos) { - // find the package in the group that is in a touched by dpkg - // if there are multiple dpkg will send us a full pkgname:arch + // find the package in the group that is touched by dpkg + // if there are multiple pkgs dpkg would send us a full pkgname:arch pkgCache::GrpIterator Grp = Cache.FindGrp(pkgname); - if (Grp.end() == false) + if (Grp.end() == false) { - pkgCache::PkgIterator P = Grp.PackageList(); - for (; P.end() != true; P = Grp.NextPkg(P)) - { - if(Cache[P].Mode != pkgDepCache::ModeKeep) - { - pkgname = P.FullName(); - break; - } - } + pkgCache::PkgIterator P = Grp.PackageList(); + for (; P.end() != true; P = Grp.NextPkg(P)) + { + if(Cache[P].Keep() == false || Cache[P].ReInstall() == true) + { + pkgname = P.FullName(); + break; + } + } } } - + const char* const pkg = pkgname.c_str(); std::string short_pkgname = StringSplit(pkgname, ":")[0]; std::string arch = ""; @@ -697,28 +699,29 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line) if (prefix == "status") { vector const &states = PackageOps[pkg]; - const char *next_action = NULL; if(PackageOpsDone[pkg] < states.size()) - next_action = states[PackageOpsDone[pkg]].state; - // check if the package moved to the next dpkg state - if(next_action && (action == next_action)) { - // only read the translation if there is actually a next - // action - const char *translation = _(states[PackageOpsDone[pkg]].str); - std::string msg; - - // we moved from one dpkg state to a new one, report that - PackageOpsDone[pkg]++; - PackagesDone++; - - strprintf(msg, translation, i18n_pkgname.c_str()); - d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg); - + char const * const next_action = states[PackageOpsDone[pkg]].state; + if (next_action && Debug == true) + std::clog << "(parsed from dpkg) pkg: " << short_pkgname + << " action: " << action << " (expected: '" << next_action << "' " + << PackageOpsDone[pkg] << " of " << states.size() << ")" << endl; + + // check if the package moved to the next dpkg state + if(next_action && (action == next_action)) + { + // only read the translation if there is actually a next action + char const * const translation = _(states[PackageOpsDone[pkg]].str); + + // we moved from one dpkg state to a new one, report that + ++PackageOpsDone[pkg]; + ++PackagesDone; + + std::string msg; + strprintf(msg, translation, i18n_pkgname.c_str()); + d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg); + } } - if (Debug == true) - std::clog << "(parsed from dpkg) pkg: " << short_pkgname - << " action: " << action << endl; } } /*}}}*/ diff --git a/test/integration/test-apt-progress-fd b/test/integration/test-apt-progress-fd index 9d250e949..d72e7e72d 100755 --- a/test/integration/test-apt-progress-fd +++ b/test/integration/test-apt-progress-fd @@ -33,6 +33,22 @@ testsuccess aptget install testing=0.8.15 -y -o APT::Status-Fd=3 testequal "dlstatus:1:0:Retrieving file 1 of 1 dlstatus:1:0:Retrieving file 1 of 1 pmstatus:dpkg-exec:0:Running dpkg +pmstatus:testing:0:Installing testing (amd64) +pmstatus:testing:20:Preparing testing (amd64) +pmstatus:testing:40:Unpacking testing (amd64) +pmstatus:testing:60:Preparing to configure testing (amd64) +pmstatus:dpkg-exec:60:Running dpkg +pmstatus:testing:60:Configuring testing (amd64) +pmstatus:testing:80:Configuring testing (amd64) +pmstatus:testing:100:Installed testing (amd64)" cat apt-progress.log + +# reinstall +exec 3> apt-progress.log +testsuccess aptget install testing=0.8.15 --reinstall -y -o APT::Status-Fd=3 +testequal "dlstatus:1:0:Retrieving file 1 of 1 +dlstatus:1:0:Retrieving file 1 of 1 +pmstatus:dpkg-exec:0:Running dpkg +pmstatus:testing:0:Installing testing (amd64) pmstatus:testing:20:Preparing testing (amd64) pmstatus:testing:40:Unpacking testing (amd64) pmstatus:testing:60:Preparing to configure testing (amd64) -- cgit v1.2.3-70-g09d2 From 22da5c135a74eee8ed998806136e25b8ed038bd0 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Tue, 9 Sep 2014 13:52:32 +0200 Subject: don't call pager in non-terminals for changelog Most pagers are nice and default to running non-interactively if they aren't connected to a terminal and we relied on that. On ci.debian.net the configured pager is printing a header out of nowhere though, so if we are printing to a non-terminal we call "cat" instead. In the rework we also "remove" the dependency on sensible-utils in sofar as we call some alternatives if calling the utils fail. This seems to be the last problem preventing a "PASS" status on ci.debian.net, so we close the associated bugreport. Closes: 755040 --- apt-private/private-utils.cc | 58 +++++++++++++++++++++++---------- apt-private/private-utils.h | 4 +-- test/integration/test-apt-get-changelog | 5 ++- 3 files changed, 45 insertions(+), 22 deletions(-) (limited to 'test') diff --git a/apt-private/private-utils.cc b/apt-private/private-utils.cc index 9547a1b75..34af83c08 100644 --- a/apt-private/private-utils.cc +++ b/apt-private/private-utils.cc @@ -8,45 +8,69 @@ #include #include -// DisplayFileInPager - Display File with pager /*{{{*/ -void DisplayFileInPager(std::string filename) +// DisplayFileInPager - Display File with pager /*{{{*/ +void DisplayFileInPager(std::string const &filename) { - std::string pager = _config->Find("Dir::Bin::Pager", - "/usr/bin/sensible-pager"); - pid_t Process = ExecFork(); if (Process == 0) { const char *Args[3]; - Args[0] = pager.c_str(); Args[1] = filename.c_str(); - Args[2] = 0; + Args[2] = NULL; + if (isatty(STDOUT_FILENO) == 1) + { + // likely installed, provided by sensible-utils + std::string const pager = _config->Find("Dir::Bin::Pager", + "sensible-pager"); + Args[0] = pager.c_str(); + execvp(Args[0],(char **)Args); + // lets try some obvious alternatives + Args[0] = getenv("PAGER"); + if (Args[0] != NULL) + execvp(Args[0],(char **)Args); + + Args[0] = "pager"; + execvp(Args[0],(char **)Args); + } + // we could read the file ourselves, but… meh + Args[0] = "cat"; execvp(Args[0],(char **)Args); exit(100); } - + // Wait for the subprocess - ExecWait(Process, "sensible-pager", false); + ExecWait(Process, "pager", false); } /*}}}*/ -// EditFileInSensibleEditor - Edit File with editor /*{{{*/ -void EditFileInSensibleEditor(std::string filename) +// EditFileInSensibleEditor - Edit File with editor /*{{{*/ +void EditFileInSensibleEditor(std::string const &filename) { - std::string editor = _config->Find("Dir::Bin::Editor", - "/usr/bin/sensible-editor"); - pid_t Process = ExecFork(); if (Process == 0) { + // likely installed, provided by sensible-utils + std::string const editor = _config->Find("Dir::Bin::Editor", + "sensible-editor"); const char *Args[3]; Args[0] = editor.c_str(); Args[1] = filename.c_str(); - Args[2] = 0; + Args[2] = NULL; + execvp(Args[0],(char **)Args); + // the usual suspects we can try as an alternative + Args[0] = getenv("VISUAL"); + if (Args[0] != NULL) + execvp(Args[0],(char **)Args); + + Args[0] = getenv("EDITOR"); + if (Args[0] != NULL) + execvp(Args[0],(char **)Args); + + Args[0] = "editor"; execvp(Args[0],(char **)Args); exit(100); } - + // Wait for the subprocess - ExecWait(Process, "sensible-editor", false); + ExecWait(Process, "editor", false); } /*}}}*/ diff --git a/apt-private/private-utils.h b/apt-private/private-utils.h index 432699787..8ba480bd4 100644 --- a/apt-private/private-utils.h +++ b/apt-private/private-utils.h @@ -5,7 +5,7 @@ #include -APT_PUBLIC void DisplayFileInPager(std::string filename); -APT_PUBLIC void EditFileInSensibleEditor(std::string filename); +APT_PUBLIC void DisplayFileInPager(std::string const &filename); +APT_PUBLIC void EditFileInSensibleEditor(std::string const &filename); #endif diff --git a/test/integration/test-apt-get-changelog b/test/integration/test-apt-get-changelog index a73c3e249..4ee113482 100755 --- a/test/integration/test-apt-get-changelog +++ b/test/integration/test-apt-get-changelog @@ -28,9 +28,8 @@ testsuccess aptget changelog apt -d testfileequal 'apt.changelog' "$(cat aptarchive/pool/apt_1.0/changelog)" rm apt.changelog aptarchive/pool/apt_1.0/changelog -aptget changelog apt -qq -o APT::Changelogs::Server='http://not-on-the-main-server:8080/' > apt.changelog -testfileequal 'apt.changelog' "$(cat aptarchive/pool/apt_1.0.changelog)" -rm apt.changelog +testequal "$(cat aptarchive/pool/apt_1.0.changelog)" aptget changelog apt \ + -qq -o APT::Changelogs::Server='http://not-on-the-main-server:8080/' testsuccess aptget changelog apt -d testfileequal 'apt.changelog' "$(cat aptarchive/pool/apt_1.0.changelog)" -- cgit v1.2.3-70-g09d2 From ca7fd76c2f30c100dcf1c12e717ce397cccd690b Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 16 Sep 2014 20:23:43 +0200 Subject: SECURITY UPDATE for CVE-2014-{0488,0487,0489} incorrect invalidating of unauthenticated data (CVE-2014-0488) incorect verification of 304 reply (CVE-2014-0487) incorrect verification of Acquire::Gzip indexes (CVE-2014-0489) --- apt-pkg/acquire-item.cc | 97 +++++++++++++++++++++++------- apt-pkg/acquire-item.h | 8 +++ apt-pkg/contrib/fileutl.h | 2 + methods/copy.cc | 32 ++++++++-- test/integration/test-apt-update-stale | 46 ++++++++++++++ test/integration/test-apt-update-unauth | 48 +++++++++++++++ test/integration/test-hashsum-verification | 14 ++++- 7 files changed, 217 insertions(+), 30 deletions(-) create mode 100755 test/integration/test-apt-update-stale create mode 100755 test/integration/test-apt-update-unauth (limited to 'test') diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 6cb9b012a..058b8bf74 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1021,6 +1021,31 @@ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ Item::Failed(Message,Cnf); } /*}}}*/ +// pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/ +std::string pkgAcqIndex::GetFinalFilename(std::string const &URI, + std::string const &compExt) +{ + std::string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(URI); + if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz") + FinalFile += ".gz"; + return FinalFile; +} + /*}}}*/ +// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/ +void pkgAcqIndex::ReverifyAfterIMS(std::string const &FileName) +{ + std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); + if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz") + DestFile += ".gz"; + + string FinalFile = GetFinalFilename(RealURI, compExt); + Rename(FinalFile, FileName); + Decompression = true; + Desc.URI = "copy:" + FileName; + QueueURI(Desc); +} + /*}}}*/ // AcqIndex::Done - Finished a fetch /*{{{*/ // --------------------------------------------------------------------- /* This goes through a number of states.. On the initial fetch the @@ -1032,6 +1057,7 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, pkgAcquire::MethodConfig *Cfg) { Item::Done(Message,Size,Hash,Cfg); + std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); if (Decompression == true) { @@ -1043,6 +1069,7 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, if (!ExpectedHash.empty() && ExpectedHash.toStr() != Hash) { + Desc.URI = RealURI; RenameOnError(HashSumMismatch); return; } @@ -1053,9 +1080,9 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, /* Always verify the index file for correctness (all indexes must * have a Package field) (LP: #346386) (Closes: #627642) */ - FileFd fd(DestFile, FileFd::ReadOnly); + FileFd fd(DestFile, FileFd::ReadOnlyGzip); // Only test for correctness if the file is not empty (empty is ok) - if (fd.FileSize() > 0) + if (fd.Size() > 0) { pkgTagSection sec; pkgTagFile tag(&fd); @@ -1069,8 +1096,7 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, } // Done, move it into position - string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(RealURI); + string FinalFile = GetFinalFilename(RealURI, compExt); Rename(DestFile,FinalFile); chmod(FinalFile.c_str(),0644); @@ -1078,7 +1104,9 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, will work OK */ DestFile = _config->FindDir("Dir::State::lists") + "partial/"; DestFile += URItoFileName(RealURI); - + if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz") + DestFile += ".gz"; + // Remove the compressed version. if (Erase == true) unlink(DestFile.c_str()); @@ -1094,7 +1122,10 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, { // The files timestamp matches if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true) - return; + { + ReverifyAfterIMS(FileName); + return; + } Decompression = true; Local = true; DestFile += ".decomp"; @@ -1111,15 +1142,12 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, ErrorText = "Method gave a blank filename"; } - std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); - // The files timestamp matches - if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) { - if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz") - // Update DestFile for .gz suffix so that the clean operation keeps it - DestFile += ".gz"; + if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) + { + ReverifyAfterIMS(FileName); return; - } + } if (FileName == DestFile) Erase = true; @@ -1128,16 +1156,16 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, string decompProg; - // If we enable compressed indexes and already have gzip, keep it - if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) { - string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(RealURI) + ".gz"; - Rename(DestFile,FinalFile); - chmod(FinalFile.c_str(),0644); - - // Update DestFile for .gz suffix so that the clean operation keeps it - DestFile = _config->FindDir("Dir::State::lists") + "partial/"; + // If we enable compressed indexes, queue for hash verification + if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) + { + DestFile = _config->FindDir("Dir::State::lists"); DestFile += URItoFileName(RealURI) + ".gz"; + + Decompression = true; + Desc.URI = "copy:" + FileName; + QueueURI(Desc); + return; } @@ -1181,6 +1209,9 @@ string pkgAcqIndexTrans::Custom600Headers() string Final = _config->FindDir("Dir::State::lists"); Final += URItoFileName(RealURI); + if (_config->FindB("Acquire::GzipIndexes",false)) + Final += ".gz"; + struct stat Buf; if (stat(Final.c_str(),&Buf) != 0) return "\nFail-Ignore: true\nIndex-File: true"; @@ -1510,6 +1541,28 @@ void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/ std::cerr << "Signature verification succeeded: " << DestFile << std::endl; + // do not trust any previously unverified content that we may have + string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI)); + if (DestFile != SigFile) + LastGoodSigFile.append(".gpg"); + LastGoodSigFile.append(".reverify"); + if(IMSHit == false && RealFileExists(LastGoodSigFile) == false) + { + for (vector ::const_iterator Target = IndexTargets->begin(); + Target != IndexTargets->end(); + ++Target) + { + // remove old indexes + std::string index = _config->FindDir("Dir::State::lists") + + URItoFileName((*Target)->URI); + unlink(index.c_str()); + // and also old gzipindexes + index += ".gz"; + unlink(index.c_str()); + } + } + + // Download further indexes with verification QueueIndexes(true); diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index 06537bf2c..384c5ee2b 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -706,6 +706,14 @@ class pkgAcqIndex : public pkgAcquire::Item */ std::string CompressionExtension; + /** \brief Get the full pathname of the final file for the given URI + */ + std::string GetFinalFilename(std::string const &URI, + std::string const &compExt); + + /** \brief Schedule file for verification after a IMS hit */ + void ReverifyAfterIMS(std::string const &FileName); + public: // Specialized action members diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index cc1a98eae..667057067 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -85,7 +85,9 @@ class FileFd bool Skip(unsigned long long To); bool Truncate(unsigned long long To); unsigned long long Tell(); + // the size of the file content (compressed files will be uncompressed first) unsigned long long Size(); + // the size of the file itself unsigned long long FileSize(); time_t ModificationTime(); diff --git a/methods/copy.cc b/methods/copy.cc index d59f032ff..5570f31c8 100644 --- a/methods/copy.cc +++ b/methods/copy.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -27,12 +28,28 @@ class CopyMethod : public pkgAcqMethod { virtual bool Fetch(FetchItem *Itm); + void CalculateHashes(FetchResult &Res); public: - CopyMethod() : pkgAcqMethod("1.0",SingleInstance) {}; + CopyMethod() : pkgAcqMethod("1.0",SingleInstance | SendConfig) {}; }; +void CopyMethod::CalculateHashes(FetchResult &Res) +{ + // For gzip indexes we need to look inside the gzip for the hash + // We can not use the extension here as its not used in partial + // on a IMS hit + FileFd::OpenMode OpenMode = FileFd::ReadOnly; + if (_config->FindB("Acquire::GzipIndexes", false) == true) + OpenMode = FileFd::ReadOnlyGzip; + + Hashes Hash; + FileFd Fd(Res.Filename, OpenMode); + Hash.AddFD(Fd); + Res.TakeHashes(Hash); +} + // CopyMethod::Fetch - Fetch a file /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -54,6 +71,14 @@ bool CopyMethod::Fetch(FetchItem *Itm) Res.IMSHit = false; URIStart(Res); + // just calc the hashes if the source and destination are identical + if (File == Itm->DestFile) + { + CalculateHashes(Res); + URIDone(Res); + return true; + } + // See if the file exists FileFd From(File,FileFd::ReadOnly); FileFd To(Itm->DestFile,FileFd::WriteAtomic); @@ -82,10 +107,7 @@ bool CopyMethod::Fetch(FetchItem *Itm) if (utimes(Res.Filename.c_str(), times) != 0) return _error->Errno("utimes",_("Failed to set modification time")); - Hashes Hash; - FileFd Fd(Res.Filename, FileFd::ReadOnly); - Hash.AddFD(Fd); - Res.TakeHashes(Hash); + CalculateHashes(Res); URIDone(Res); return true; diff --git a/test/integration/test-apt-update-stale b/test/integration/test-apt-update-stale new file mode 100755 index 000000000..780ff79af --- /dev/null +++ b/test/integration/test-apt-update-stale @@ -0,0 +1,46 @@ +#!/bin/sh +# +# Ensure that a MITM can not stale the Packages/Sources without +# raising a error message. Note that the Release file is protected +# via the "Valid-Until" header +# +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework + +setupenvironment +configarchitecture "i386" + +insertpackage 'unstable' 'foo' 'all' '1.0' + +setupaptarchive +changetowebserver +aptget update -qq + +# insert new version +mkdir aptarchive/dists/unstable/main/binary-i386/saved +cp -p aptarchive/dists/unstable/main/binary-i386/Packages* \ + aptarchive/dists/unstable/main/binary-i386/saved +insertpackage 'unstable' 'foo' 'all' '2.0' + +# not using compressfile for compat with older apt releases +gzip -c aptarchive/dists/unstable/main/binary-i386/Packages > \ + aptarchive/dists/unstable/main/binary-i386/Packages.gz +generatereleasefiles +signreleasefiles + +# ensure that we do not get a I-M-S hit for the Release file +touch -d "+1hour" aptarchive/dists/unstable/*Release* + +# but now only deliver the previous Packages file instead of the new one +# (simulating a stale attack) +cp -p aptarchive/dists/unstable/main/binary-i386/saved/Packages* \ + aptarchive/dists/unstable/main/binary-i386/ + +# ensure this raises a error +testequal "W: Failed to fetch http://localhost:8080/dists/unstable/main/binary-i386/Packages Hash Sum mismatch + +E: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq + + diff --git a/test/integration/test-apt-update-unauth b/test/integration/test-apt-update-unauth new file mode 100755 index 000000000..13487603c --- /dev/null +++ b/test/integration/test-apt-update-unauth @@ -0,0 +1,48 @@ +#!/bin/sh +# +# Ensure that when going from unauthenticated to authenticated all +# files are checked again +# +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework + +setupenvironment +configarchitecture "i386" + +insertpackage 'unstable' 'foo' 'all' '1.0' +insertsource 'unstable' 'foo' 'all' '1.0' + +setupaptarchive +changetowebserver + +runtest() { + # start unauthenticated + find rootdir/var/lib/apt/lists/ -type f | xargs rm -f + rm -f aptarchive/dists/unstable/*Release* + aptget update -qq + + # become authenticated + generatereleasefiles + signreleasefiles + + # and ensure we do download the data again + msgtest "Check that the data is check when going to authenticated" + if aptget update |grep -q Hit; then + msgfail + else + msgpass + fi +} + +for COMPRESSEDINDEXES in 'false' 'true'; do + echo "Acquire::GzipIndexes \"$COMPRESSEDINDEXES\";" > rootdir/etc/apt/apt.conf.d/compressindexes + if $COMPRESSEDINDEXES; then + msgmsg 'Run tests with GzipIndexes enabled' + else + msgmsg 'Run tests with GzipIndexes disabled' + fi + + runtest +done diff --git a/test/integration/test-hashsum-verification b/test/integration/test-hashsum-verification index e77efb46e..2a400dcb4 100755 --- a/test/integration/test-hashsum-verification +++ b/test/integration/test-hashsum-verification @@ -64,7 +64,7 @@ runtest() { msgtest 'No package from the source available' [ "$(aptcache show apt 2>&1)" = "E: No packages found" ] && msgpass || msgfail msgtest 'No Packages file in /var/lib/apt/lists' - [ "$(ls rootdir/var/lib/apt/lists/*Package* 2>/dev/null)" = "" ] && msgpass || msgfail + [ "$(ls rootdir/var/lib/apt/lists/*Package* 2>/dev/null | grep -v FAILED 2>/dev/null)" = "" ] && msgpass || msgfail # now with the unsigned Release file rm -rf rootdir/var/lib/apt/lists @@ -75,5 +75,13 @@ runtest() { } -runtest - +for COMPRESSEDINDEXES in 'false' 'true'; do + echo "Acquire::GzipIndexes \"$COMPRESSEDINDEXES\";" > rootdir/etc/apt/apt.conf.d/compressindexes + if $COMPRESSEDINDEXES; then + msgmsg 'Run tests with GzipIndexes enabled' + else + msgmsg 'Run tests with GzipIndexes disabled' + fi + + runtest +done -- cgit v1.2.3-70-g09d2 From daff4aa356128310f022370f7825bdc369c66ba8 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 17 Sep 2014 14:57:05 +0200 Subject: Fix regression for file:/// uris from CVE-2014-0487 Do not run ReverifyAfterIMS() for local file URIs as this will causes apt to mess around in the file:/// uri space. This is wrong in itself, but it will also cause a incorrect verification failure when the archive and the lists directory are on different partitions as rename(). --- apt-pkg/acquire-item.cc | 18 ++++++------------ test/integration/test-apt-update-file | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 12 deletions(-) create mode 100755 test/integration/test-apt-update-file (limited to 'test') diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 058b8bf74..2ced65aa2 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1120,12 +1120,6 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, string FileName = LookupTag(Message,"Alt-Filename"); if (FileName.empty() == false) { - // The files timestamp matches - if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true) - { - ReverifyAfterIMS(FileName); - return; - } Decompression = true; Local = true; DestFile += ".decomp"; @@ -1142,18 +1136,18 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, ErrorText = "Method gave a blank filename"; } + if (FileName == DestFile) + Erase = true; + else + Local = true; + // The files timestamp matches - if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) + if (!Local && StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) { ReverifyAfterIMS(FileName); return; } - if (FileName == DestFile) - Erase = true; - else - Local = true; - string decompProg; // If we enable compressed indexes, queue for hash verification diff --git a/test/integration/test-apt-update-file b/test/integration/test-apt-update-file new file mode 100755 index 000000000..069f8ba2f --- /dev/null +++ b/test/integration/test-apt-update-file @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Ensure that we do not modify file:/// uris (regression test for +# CVE-2014-0487 +# +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework + +setupenvironment +configarchitecture "amd64" +configcompression 'bz2' 'gz' + +insertpackage 'unstable' 'foo' 'all' '1.0' + +umask 022 +setupaptarchive --no-update + +# ensure the archive is not writable +chmod 550 aptarchive/dists/unstable/main/binary-amd64 + +testsuccess aptget update -qq +testsuccess aptget update -qq + +# the cleanup should still work +chmod 750 aptarchive/dists/unstable/main/binary-amd64 -- cgit v1.2.3-70-g09d2 From 23d0a6fbee9e8880107481502e14411961c44a7b Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 17 Sep 2014 17:48:27 +0200 Subject: improve test for commit daff4a --- apt-pkg/acquire-item.cc | 5 +++-- test/integration/test-apt-update-file | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 2ced65aa2..5df43726b 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1141,13 +1141,14 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, else Local = true; - // The files timestamp matches + // The files timestamp matches, for non-local URLs reverify the local + // file, for local file, uncompress again to ensure the hashsum is still + // matching the Release file if (!Local && StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) { ReverifyAfterIMS(FileName); return; } - string decompProg; // If we enable compressed indexes, queue for hash verification diff --git a/test/integration/test-apt-update-file b/test/integration/test-apt-update-file index 069f8ba2f..e267c71da 100755 --- a/test/integration/test-apt-update-file +++ b/test/integration/test-apt-update-file @@ -22,6 +22,13 @@ chmod 550 aptarchive/dists/unstable/main/binary-amd64 testsuccess aptget update -qq testsuccess aptget update -qq +aptget update -qq -o Debug::pkgAcquire::Auth=1 2> output.log + +# ensure that the hash of the uncompressed file was verified even on a local +# ims hit +canary="SHA512:$(bzcat aptarchive/dists/unstable/main/binary-amd64/Packages.bz2 | sha512sum |cut -f1 -d' ')" +grep -q "RecivedHash: $canary" output.log + # the cleanup should still work chmod 750 aptarchive/dists/unstable/main/binary-amd64 -- cgit v1.2.3-70-g09d2 From 8b451962751298876d1f399e4de492d8adbb135a Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 19 Sep 2014 16:41:50 +0200 Subject: test/integration/test-apt-update-file: improve test --- test/integration/test-apt-update-file | 2 ++ test/integration/test-bug-762160-relpath | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100755 test/integration/test-bug-762160-relpath (limited to 'test') diff --git a/test/integration/test-apt-update-file b/test/integration/test-apt-update-file index e267c71da..fbcd473cc 100755 --- a/test/integration/test-apt-update-file +++ b/test/integration/test-apt-update-file @@ -29,6 +29,8 @@ aptget update -qq -o Debug::pkgAcquire::Auth=1 2> output.log canary="SHA512:$(bzcat aptarchive/dists/unstable/main/binary-amd64/Packages.bz2 | sha512sum |cut -f1 -d' ')" grep -q "RecivedHash: $canary" output.log +# foo is still available +testsuccess aptget install -s foo # the cleanup should still work chmod 750 aptarchive/dists/unstable/main/binary-amd64 diff --git a/test/integration/test-bug-762160-relpath b/test/integration/test-bug-762160-relpath new file mode 100755 index 000000000..0af71f57b --- /dev/null +++ b/test/integration/test-bug-762160-relpath @@ -0,0 +1,15 @@ +#!/bin/sh +set -e + +# dpkg implements versioned provides in commit 5bb02fe80e9f40dcad9703a72f67cf615ff217b5 +# but previous versions seem to allow parsing, working and ignoring it. + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework +setupenvironment +configarchitecture 'amd64' + +insertpackage 'unstable' 'foo' 'all' '1' +setupaptarchive + +aptget update -o Dir=./apt -- cgit v1.2.3-70-g09d2 From 9da539c5aff025aab99537be1c75e8c6a853fd83 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 19 Sep 2014 16:41:55 +0200 Subject: Fix regression when copy: is used for a relative path When we do a ReverifyAfterIMS() we use the copy: method to verify the hashes again. If the user uses -o Dir=./something/relative this fails because we use the URI class in copy.cc that strips away the leading relative part. By not using URI this is fixed. Closes: #762160 --- methods/copy.cc | 4 ++-- test/integration/test-bug-762160-relpath | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/methods/copy.cc b/methods/copy.cc index 5570f31c8..b78053d36 100644 --- a/methods/copy.cc +++ b/methods/copy.cc @@ -55,8 +55,8 @@ void CopyMethod::CalculateHashes(FetchResult &Res) /* */ bool CopyMethod::Fetch(FetchItem *Itm) { - URI Get = Itm->Uri; - std::string File = Get.Path; + // this ensures that relative paths work in copy + std::string File = Itm->Uri.substr(Itm->Uri.find(':')+1); // Stat the file and send a start message struct stat Buf; diff --git a/test/integration/test-bug-762160-relpath b/test/integration/test-bug-762160-relpath index 0af71f57b..204587727 100755 --- a/test/integration/test-bug-762160-relpath +++ b/test/integration/test-bug-762160-relpath @@ -1,9 +1,9 @@ #!/bin/sh +# regresion test for bug #762160 where apt-get update fails when a +# relative directory is given +# set -e -# dpkg implements versioned provides in commit 5bb02fe80e9f40dcad9703a72f67cf615ff217b5 -# but previous versions seem to allow parsing, working and ignoring it. - TESTDIR=$(readlink -f $(dirname $0)) . $TESTDIR/framework setupenvironment @@ -11,5 +11,7 @@ configarchitecture 'amd64' insertpackage 'unstable' 'foo' 'all' '1' setupaptarchive +changetowebserver -aptget update -o Dir=./apt +testsuccess aptget update -o Dir=./rootdir +testsuccess aptget update -o Dir=./rootdir \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2bd6be8ad24583ed9935f5c5d57c04ba7344111e Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 20 Sep 2014 00:12:13 +0200 Subject: relax grep to support newer curl output format Git-Dch: Ignore --- test/integration/test-apt-https-no-redirect | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/integration/test-apt-https-no-redirect b/test/integration/test-apt-https-no-redirect index 73352a28c..bc744d6f2 100755 --- a/test/integration/test-apt-https-no-redirect +++ b/test/integration/test-apt-https-no-redirect @@ -25,6 +25,11 @@ msgtest 'download of a file does not work if' 'https redirected to http' downloadfile 'https://localhost:4433/redirectme/working' redirectfile >curloutput 2>&1 && msgfail || msgpass msgtest 'libcurl has forbidden access in last request to' 'http resource' -grep -q -- 'Protocol http not supported or disabled in libcurl' curloutput && msgpass || msgfail +if grep -q -E -- 'Protocol "?http"? not supported or disabled in libcurl' curloutput; then + msgpass +else + cat curloutput + msgfail +fi -- cgit v1.2.3-70-g09d2