diff options
author | Julian Andres Klode <julian.klode@canonical.com> | 2019-01-23 13:57:45 +0100 |
---|---|---|
committer | Julian Andres Klode <julian.klode@canonical.com> | 2019-01-30 13:33:24 +0100 |
commit | 711cda2302b0dfe5d4ab0588b245ae4a97863e5b (patch) | |
tree | 1b9a017af0495a8479e284cbe1f4a4c45712a959 /apt-pkg | |
parent | 4200469bb5a14c4659285917ed30c46a0b15c286 (diff) | |
download | apt-711cda2302b0dfe5d4ab0588b245ae4a97863e5b.tar.gz |
Verify data being sent by methods in SendMessage()
As a follow-up for CVE-2019-3462, add checks similar to those
for redirect to the central SendMessage() function. The checks
are a bit more relaxed for values - they may include newlines
and unicode characters (newlines get rewritten, so are safe).
For keys and the message header, the checks are far more strict:
They may only contain alphanumerical characters, the hyphen-minus,
and the horizontal space.
In case the method tries to send anything else, we construct a
legal 400 URI Failed response, and send that. We specifically do
not include the item URI, in case it has been compromised (that
would cause infinite recursion).
Diffstat (limited to 'apt-pkg')
-rw-r--r-- | apt-pkg/acquire-method.cc | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/apt-pkg/acquire-method.cc b/apt-pkg/acquire-method.cc index c67c47ab8..ae5ae4a15 100644 --- a/apt-pkg/acquire-method.cc +++ b/apt-pkg/acquire-method.cc @@ -88,6 +88,37 @@ pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags) /*}}}*/ void pkgAcqMethod::SendMessage(std::string const &header, std::unordered_map<std::string, std::string> &&fields) /*{{{*/ { + auto CheckKey = [](std::string const &str) { + // Space, hyphen-minus, and alphanum are allowed for keys/headers. + return str.find_first_not_of(" -0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") == std::string::npos; + }; + + auto CheckValue = [](std::string const &str) { + return std::all_of(str.begin(), str.end(), [](unsigned char c) -> bool { + return c > 127 // unicode + || (c > 31 && c < 127) // printable chars + || c == '\n' || c == '\t'; // special whitespace + }); + }; + + auto Error = [this]() { + _error->Error("SECURITY: Message contains control characters, rejecting."); + _error->DumpErrors(); + SendMessage("400 URI Failure", {{"URI", "<UNKNOWN>"}, {"Message", "SECURITY: Message contains control characters, rejecting."}}); + abort(); + }; + + if (!CheckKey(header)) + return Error(); + + for (auto const &f : fields) + { + if (!CheckKey(f.first)) + return Error(); + if (!CheckValue(f.second)) + return Error(); + } + std::cout << header << '\n'; for (auto const &f : fields) { |