summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2018-02-19 15:06:06 +0000
committerJulian Andres Klode <jak@debian.org>2018-02-19 15:06:06 +0000
commit928ecff984be22632c27a69e072741e74491292c (patch)
treef0d760cc2da3841b90e7f067fd39dbc355c971c8
parent13c85c9cec9e071e90ea190a74cbaabe7c51024c (diff)
parent9e5899cac1a6367e3769af52a724821880e538f6 (diff)
Merge branch 'pu/not-valid-before' into 'master'
Check that Date of Release file is not in the future See merge request apt-team/apt!3
-rw-r--r--apt-pkg/acquire-item.cc19
-rw-r--r--apt-pkg/deb/debmetaindex.cc136
-rw-r--r--apt-pkg/deb/debmetaindex.h4
-rw-r--r--apt-pkg/metaindex.cc7
-rw-r--r--apt-pkg/metaindex.h1
-rw-r--r--apt-pkg/sourcelist.cc2
-rw-r--r--debian/NEWS16
-rw-r--r--doc/apt.conf.5.xml21
-rw-r--r--doc/examples/configure-index3
-rw-r--r--doc/sources.list.5.xml17
-rw-r--r--test/integration/framework2
-rwxr-xr-xtest/integration/test-releasefile-date46
12 files changed, 231 insertions, 43 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc
index 86ffe9e49..21d990fba 100644
--- a/apt-pkg/acquire-item.cc
+++ b/apt-pkg/acquire-item.cc
@@ -1661,6 +1661,25 @@ bool pkgAcqMetaBase::VerifyVendor(string const &) /*{{{*/
}
}
+ if (TransactionManager->MetaIndexParser->GetNotBefore() > 0)
+ {
+ time_t const invalid_for = TransactionManager->MetaIndexParser->GetNotBefore() - time(nullptr);
+ if (invalid_for > 0)
+ {
+ std::string errmsg;
+ strprintf(errmsg,
+ // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
+ // the time until the file will be valid - formatted in the same way as in
+ // the download progress display (e.g. 7d 3h 42min 1s)
+ _("Release file for %s is not valid yet (invalid for another %s). "
+ "Updates for this repository will not be applied."),
+ Target.URI.c_str(), TimeToStr(invalid_for).c_str());
+ if (ErrorText.empty())
+ ErrorText = errmsg;
+ return _error->Error("%s", errmsg.c_str());
+ }
+ }
+
/* Did we get a file older than what we have? This is a last minute IMS hit and doubles
as a prevention of downgrading us to older (still valid) files */
if (TransactionManager->IMSHit == false && TransactionManager->LastMetaIndexParser != NULL &&
diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc
index 59a26390e..6cbed85a7 100644
--- a/apt-pkg/deb/debmetaindex.cc
+++ b/apt-pkg/deb/debmetaindex.cc
@@ -49,12 +49,16 @@ class APT_HIDDEN debReleaseIndexPrivate /*{{{*/
time_t ValidUntilMin;
time_t ValidUntilMax;
+ metaIndex::TriState CheckDate;
+ time_t DateMaxFuture;
+ time_t NotBefore;
+
std::vector<std::string> Architectures;
std::vector<std::string> NoSupportForAll;
std::vector<std::string> SupportedComponents;
std::map<std::string, std::string> const ReleaseOptions;
- debReleaseIndexPrivate(std::map<std::string, std::string> const &Options) : CheckValidUntil(metaIndex::TRI_UNSET), ValidUntilMin(0), ValidUntilMax(0), ReleaseOptions(Options) {}
+ debReleaseIndexPrivate(std::map<std::string, std::string> const &Options) : CheckValidUntil(metaIndex::TRI_UNSET), ValidUntilMin(0), ValidUntilMax(0), CheckDate(metaIndex::TRI_UNSET), DateMaxFuture(0), NotBefore(0), ReleaseOptions(Options) {}
};
/*}}}*/
// ReleaseIndex::MetaIndex* - display helpers /*{{{*/
@@ -482,54 +486,77 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro
Date = 0;
}
- bool CheckValidUntil = _config->FindB("Acquire::Check-Valid-Until", true);
- if (d->CheckValidUntil == metaIndex::TRI_NO)
- CheckValidUntil = false;
- else if (d->CheckValidUntil == metaIndex::TRI_YES)
- CheckValidUntil = true;
+ bool CheckDate = _config->FindB("Acquire::Check-Date", true);
+ if (d->CheckDate == metaIndex::TRI_NO)
+ CheckDate = false;
+ else if (d->CheckDate == metaIndex::TRI_YES)
+ CheckDate = true;
- if (CheckValidUntil == true)
+ if (CheckDate)
{
- std::string const StrValidUntil = Section.FindS("Valid-Until");
-
- // if we have a Valid-Until header in the Release file, use it as default
- if (StrValidUntil.empty() == false)
- {
- if(RFC1123StrToTime(StrValidUntil.c_str(), ValidUntil) == false)
- {
- if (ErrorText != NULL)
- strprintf(*ErrorText, _("Invalid '%s' entry in Release file %s"), "Valid-Until", Filename.c_str());
- return false;
- }
- }
auto const Label = GetLabel();
- // get the user settings for this archive and use what expires earlier
- time_t MaxAge = d->ValidUntilMax;
- if (MaxAge == 0)
- {
- MaxAge = _config->FindI("Acquire::Max-ValidTime", 0);
- if (Label.empty() == false)
- MaxAge = _config->FindI(("Acquire::Max-ValidTime::" + Label).c_str(), MaxAge);
- }
- time_t MinAge = d->ValidUntilMin;
- if (MinAge == 0)
+ // get the user settings for this archive
+ time_t MaxFuture = d->DateMaxFuture;
+ if (MaxFuture == 0)
{
- MinAge = _config->FindI("Acquire::Min-ValidTime", 0);
+ MaxFuture = _config->FindI("Acquire::Max-FutureTime", 10);
if (Label.empty() == false)
- MinAge = _config->FindI(("Acquire::Min-ValidTime::" + Label).c_str(), MinAge);
+ MaxFuture = _config->FindI(("Acquire::Max-FutureTime::" + Label).c_str(), MaxFuture);
}
- if (MinAge != 0 || ValidUntil != 0 || MaxAge != 0)
+ d->NotBefore = Date - MaxFuture;
+
+ bool CheckValidUntil = _config->FindB("Acquire::Check-Valid-Until", true);
+ if (d->CheckValidUntil == metaIndex::TRI_NO)
+ CheckValidUntil = false;
+ else if (d->CheckValidUntil == metaIndex::TRI_YES)
+ CheckValidUntil = true;
+
+ if (CheckValidUntil == true)
{
- if (MinAge != 0 && ValidUntil != 0) {
- time_t const min_date = Date + MinAge;
- if (ValidUntil < min_date)
- ValidUntil = min_date;
+ std::string const StrValidUntil = Section.FindS("Valid-Until");
+
+ // if we have a Valid-Until header in the Release file, use it as default
+ if (StrValidUntil.empty() == false)
+ {
+ if (RFC1123StrToTime(StrValidUntil.c_str(), ValidUntil) == false)
+ {
+ if (ErrorText != NULL)
+ strprintf(*ErrorText, _("Invalid '%s' entry in Release file %s"), "Valid-Until", Filename.c_str());
+ return false;
+ }
+ }
+ auto const Label = GetLabel();
+ // get the user settings for this archive and use what expires earlier
+ time_t MaxAge = d->ValidUntilMax;
+ if (MaxAge == 0)
+ {
+ MaxAge = _config->FindI("Acquire::Max-ValidTime", 0);
+ if (Label.empty() == false)
+ MaxAge = _config->FindI(("Acquire::Max-ValidTime::" + Label).c_str(), MaxAge);
+ }
+ time_t MinAge = d->ValidUntilMin;
+ if (MinAge == 0)
+ {
+ MinAge = _config->FindI("Acquire::Min-ValidTime", 0);
+ if (Label.empty() == false)
+ MinAge = _config->FindI(("Acquire::Min-ValidTime::" + Label).c_str(), MinAge);
}
- if (MaxAge != 0 && Date != 0) {
- time_t const max_date = Date + MaxAge;
- if (ValidUntil == 0 || ValidUntil > max_date)
- ValidUntil = max_date;
+
+ if (MinAge != 0 || ValidUntil != 0 || MaxAge != 0)
+ {
+ if (MinAge != 0 && ValidUntil != 0)
+ {
+ time_t const min_date = Date + MinAge;
+ if (ValidUntil < min_date)
+ ValidUntil = min_date;
+ }
+ if (MaxAge != 0 && Date != 0)
+ {
+ time_t const max_date = Date + MaxAge;
+ if (ValidUntil == 0 || ValidUntil > max_date)
+ ValidUntil = max_date;
+ }
}
}
}
@@ -566,6 +593,11 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro
return AuthPossible;
}
/*}}}*/
+time_t debReleaseIndex::GetNotBefore() const /*{{{*/
+{
+ return d->NotBefore;
+}
+ /*}}}*/
metaIndex * debReleaseIndex::UnloadedClone() const /*{{{*/
{
if (Trusted == TRI_NO)
@@ -685,6 +717,22 @@ bool debReleaseIndex::SetValidUntilMax(time_t const Valid)
return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Max-ValidTime", URI.c_str(), Dist.c_str());
return true;
}
+bool debReleaseIndex::SetCheckDate(TriState const pCheckDate)
+{
+ if (d->CheckDate == TRI_UNSET)
+ d->CheckDate = pCheckDate;
+ else if (d->CheckDate != pCheckDate)
+ return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Check-Date", URI.c_str(), Dist.c_str());
+ return true;
+}
+bool debReleaseIndex::SetDateMaxFuture(time_t const DateMaxFuture)
+{
+ if (d->DateMaxFuture == 0)
+ d->DateMaxFuture = DateMaxFuture;
+ else if (d->DateMaxFuture != DateMaxFuture)
+ return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Date-Max-Future", URI.c_str(), Dist.c_str());
+ return true;
+}
bool debReleaseIndex::SetSignedBy(std::string const &pSignedBy)
{
if (SignedBy.empty() == true && pSignedBy.empty() == false)
@@ -1168,9 +1216,11 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
);
if (Deb->SetTrusted(GetTriStateOption(Options, "trusted")) == false ||
- Deb->SetCheckValidUntil(GetTriStateOption(Options, "check-valid-until")) == false ||
- Deb->SetValidUntilMax(GetTimeOption(Options, "valid-until-max")) == false ||
- Deb->SetValidUntilMin(GetTimeOption(Options, "valid-until-min")) == false)
+ Deb->SetCheckValidUntil(GetTriStateOption(Options, "check-valid-until")) == false ||
+ Deb->SetValidUntilMax(GetTimeOption(Options, "valid-until-max")) == false ||
+ Deb->SetValidUntilMin(GetTimeOption(Options, "valid-until-min")) == false ||
+ Deb->SetCheckDate(GetTriStateOption(Options, "check-date")) == false ||
+ Deb->SetDateMaxFuture(GetTimeOption(Options, "date-max-future")) == false)
return false;
std::map<std::string, std::string>::const_iterator const signedby = Options.find("signed-by");
diff --git a/apt-pkg/deb/debmetaindex.h b/apt-pkg/deb/debmetaindex.h
index 5a97cfc78..864ac3eba 100644
--- a/apt-pkg/deb/debmetaindex.h
+++ b/apt-pkg/deb/debmetaindex.h
@@ -55,6 +55,8 @@ class APT_HIDDEN debReleaseIndex : public metaIndex
bool SetCheckValidUntil(TriState const Trusted);
bool SetValidUntilMin(time_t const Valid);
bool SetValidUntilMax(time_t const Valid);
+ bool SetCheckDate(TriState const CheckDate);
+ bool SetDateMaxFuture(time_t const DateMaxFuture);
bool SetSignedBy(std::string const &SignedBy);
std::map<std::string, std::string> GetReleaseOptions();
@@ -63,6 +65,8 @@ class APT_HIDDEN debReleaseIndex : public metaIndex
bool IsArchitectureAllSupportedFor(IndexTarget const &target) const;
bool HasSupportForComponent(std::string const &component) const;
+ APT_PURE time_t GetNotBefore() const;
+
void AddComponent(std::string const &sourcesEntry,
bool const isSrc, std::string const &Name,
std::vector<std::string> const &Targets,
diff --git a/apt-pkg/metaindex.cc b/apt-pkg/metaindex.cc
index bdae6dcc9..8cbdb5e01 100644
--- a/apt-pkg/metaindex.cc
+++ b/apt-pkg/metaindex.cc
@@ -72,6 +72,13 @@ APT_PURE std::string metaIndex::GetReleaseNotes() const { return d->ReleaseNotes
APT_PURE signed short metaIndex::GetDefaultPin() const { return d->DefaultPin; }
APT_PURE bool metaIndex::GetSupportsAcquireByHash() const { return SupportsAcquireByHash; }
APT_PURE time_t metaIndex::GetValidUntil() const { return ValidUntil; }
+APT_PURE time_t metaIndex::GetNotBefore() const
+{
+ debReleaseIndex const *const deb = dynamic_cast<debReleaseIndex const *>(this);
+ if (deb != nullptr)
+ return deb->GetNotBefore();
+ return 0;
+}
APT_PURE time_t metaIndex::GetDate() const { return this->Date; }
APT_PURE metaIndex::TriState metaIndex::GetLoadedSuccessfully() const { return LoadedSuccessfully; }
APT_PURE std::string metaIndex::GetExpectedDist() const { return Dist; }
diff --git a/apt-pkg/metaindex.h b/apt-pkg/metaindex.h
index 91cfce59b..08664305e 100644
--- a/apt-pkg/metaindex.h
+++ b/apt-pkg/metaindex.h
@@ -82,6 +82,7 @@ public:
bool GetSupportsAcquireByHash() const;
time_t GetValidUntil() const;
time_t GetDate() const;
+ APT_HIDDEN time_t GetNotBefore() const; // FIXME make virtual
std::string GetExpectedDist() const;
bool CheckDist(std::string const &MaybeDist) const;
diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc
index fd0264ff1..1fdc92dcb 100644
--- a/apt-pkg/sourcelist.cc
+++ b/apt-pkg/sourcelist.cc
@@ -119,6 +119,8 @@ bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List, /*{{{*/
mapping.insert(std::make_pair("Check-Valid-Until", std::make_pair("check-valid-until", false)));
mapping.insert(std::make_pair("Valid-Until-Min", std::make_pair("valid-until-min", false)));
mapping.insert(std::make_pair("Valid-Until-Max", std::make_pair("valid-until-max", false)));
+ mapping.insert(std::make_pair("Check-Date", std::make_pair("check-date", false)));
+ mapping.insert(std::make_pair("Date-Max-Future", std::make_pair("date-max-future", false)));
mapping.insert(std::make_pair("Signed-By", std::make_pair("signed-by", false)));
mapping.insert(std::make_pair("PDiffs", std::make_pair("pdiffs", false)));
mapping.insert(std::make_pair("By-Hash", std::make_pair("by-hash", false)));
diff --git a/debian/NEWS b/debian/NEWS
index 132920b5d..a8cd8f7ad 100644
--- a/debian/NEWS
+++ b/debian/NEWS
@@ -1,3 +1,19 @@
+apt (1.6~alpha8) UNRELEASED; urgency=medium
+
+ APT now verifies that the date of Release files is not in the future. By
+ default, it may be 10 seconds in the future to allow for some clock drift.
+
+ Two new configuration options can be used to tweak the behavior:
+ Acquire::Check-Date
+ Acquire::Max-DateFuture
+
+ These can be overridden in sources.list entries using the check-date
+ and date-future-max options. Note that disabling check-date also
+ disables checks on valid-until: It is considered to mean that your
+ machine's time is not reliable.
+
+ -- Julian Andres Klode <juliank@ubuntu.com> Mon, 12 Feb 2018 12:53:18 +0100
+
apt (1.6~alpha1) unstable; urgency=medium
All methods provided by apt except for cdrom, gpgv, and rsh now
diff --git a/doc/apt.conf.5.xml b/doc/apt.conf.5.xml
index fdcd99425..e285b3130 100644
--- a/doc/apt.conf.5.xml
+++ b/doc/apt.conf.5.xml
@@ -315,6 +315,27 @@ APT::Compressor::rev {
for the download itself (see also &sources-list;).</para>
<variablelist>
+ <varlistentry><term><option>Check-Date</option></term>
+ <listitem><para>
+ Security related option defaulting to true, enabling time-related
+ checks. Disabling it means that the machine's time cannot be
+ trusted, and APT will hence disable all time-related checks,
+ such as <option>Check-Valid-Until</option> and verifying that
+ the Date field of a release file is not in the future.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>Max-FutureTime</option></term>
+ <listitem><para>Maximum time (in seconds) before its creation (as indicated
+ by the <literal>Date</literal> header) that the <filename>Release</filename>
+ file should be considered valid.
+
+ The default value is <literal>10</literal>.
+ Archive specific settings can be made by appending the label of the archive
+ to the option name. Preferably, the same can be achieved for specific
+ &sources-list; entries by using the <option>Date-Max-Future</option> option there.
+ </para></listitem>
+ </varlistentry>
<varlistentry><term><option>Check-Valid-Until</option></term>
<listitem><para>
Security related option defaulting to true, as giving a Release file's
diff --git a/doc/examples/configure-index b/doc/examples/configure-index
index 00c2ee183..3763aa900 100644
--- a/doc/examples/configure-index
+++ b/doc/examples/configure-index
@@ -234,6 +234,9 @@ Acquire
Max-ValidTime::* "<INT>"; // repository label specific configuration
Min-ValidTime "<INT>"; // time in seconds
Min-ValidTime::* "<INT>"; // repository label specific configuration
+ Check-Date "<BOOL>"; // whether to check the "Date" field
+ Max-FutureTime "<INT>"; // seconds to allow release file's Date field to be in the future (default 10)
+ Max-FutureTime::* "<INT>"; // repository label specific configuration
SameMirrorForAllIndexes "<BOOL>"; // use the mirror serving the Release file for Packages & co
diff --git a/doc/sources.list.5.xml b/doc/sources.list.5.xml
index 2a047c83b..592227dd8 100644
--- a/doc/sources.list.5.xml
+++ b/doc/sources.list.5.xml
@@ -343,6 +343,23 @@ deb-src [ option1=value1 option2=value2 ] uri suite [component1] [component2] [.
default.
</para></listitem>
+ <listitem><para><option>Check-Date</option> (<option>check-date</option>)
+ is a yes/no value which controls if APT should consider
+ the machine's time correct and hence perform time related
+ checks, such as verifying that a Release file is not
+ from the future. Disabling it also disables the
+ <option>Check-Valid-Until</option> option
+ mentioned above.
+ </para></listitem>
+
+ <listitem><para><option>Date-Max-Future</option>
+ (<option>date-max-future</option>) controls how far
+ from the future a repository may be.
+ Default to the value of the configuration option
+ <option>Acquire::Max-FutureTime</option> which is
+ 10 seconds by default.
+ </para></listitem>
+
<listitem><para><option>InRelease-Path</option> (<option>inrelease-path</option>)
determines the path to the InRelease file, relative
to the normal position of an <filename>InRelease</filename> file.
diff --git a/test/integration/framework b/test/integration/framework
index ab91c8553..cf0a02de3 100644
--- a/test/integration/framework
+++ b/test/integration/framework
@@ -460,6 +460,8 @@ EOF
echo "Apt::Cmd::Disable-Script-Warning \"1\";" > rootdir/etc/apt/apt.conf.d/apt-binary
export APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=no
echo 'Acquire::Connect::AddrConfig "false";' > rootdir/etc/apt/apt.conf.d/connect-addrconfig
+ # Allow release files to be 10 hours in the future, rather than 10 seconds
+ echo 'Acquire::Max-FutureTime "'$((10 * 60 * 60))'";' > rootdir/etc/apt/apt.conf.d/future-time
configcompression '.' 'gz' #'bz2' 'lzma' 'xz'
confighashes 'SHA256' # these are tests, not security best-practices
diff --git a/test/integration/test-releasefile-date b/test/integration/test-releasefile-date
new file mode 100755
index 000000000..a98507408
--- /dev/null
+++ b/test/integration/test-releasefile-date
@@ -0,0 +1,46 @@
+#!/bin/sh
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "$TESTDIR/framework"
+setupenvironment
+configarchitecture 'i386'
+
+insertpackage 'wheezy' 'apt' 'all' '0.8.15'
+
+getlabelfromsuite() {
+ echo -n 'Testcases'
+}
+
+setupaptarchive --no-update
+
+runtest() {
+ local MSG="$1"
+ msgtest "Release file is $MSG as it has" "$2"
+ rm -rf rootdir/var/lib/apt/lists
+ generatereleasefiles "$3"
+ signreleasefiles
+ shift 3
+ if [ "$MSG" = 'accepted' ]; then
+ testsuccess --nomsg aptget update "$@"
+ testfailure grep -q 'is not valid yet' rootdir/tmp/testsuccess.output
+ else
+ testfailure --nomsg aptget update "$@"
+ testsuccess grep -q 'is not valid yet' rootdir/tmp/testfailure.output
+ fi
+}
+
+
+runtest 'accepted' 'no date' ''
+runtest 'accepted' 'ok date' 'now + 1 hour'
+runtest 'rejected' 'date to far in the future' 'now + 12 hours'
+runtest 'accepted' 'date to far in the future, but accepted via option' 'now + 12 hours' -o Acquire::Max-FutureTime=86400
+
+sed -i -e 's#\(deb\(-src\)\?\) #\1 [check-date=no] #' rootdir/etc/apt/sources.list.d/*
+runtest 'accepted' 'bad Date but overridden by sources option' 'now + 1 day'
+
+sed -i -e 's#\(deb\(-src\)\?\) \[.*\] #\1 [date-max-future=86400] #' rootdir/etc/apt/sources.list.d/*
+runtest 'accepted' 'Date allowed via sources list option via sources option' 'now + 12 hours'
+
+sed -i -e 's#\(deb\(-src\)\?\) \[.*\] #\1 [date-max-future=86405] #' rootdir/etc/apt/sources.list.d/*
+runtest 'rejected' 'Date further in the future than allowed by sources.list option' 'now + 2 day'