summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <julian.klode@canonical.com>2019-01-23 13:57:45 +0100
committerJulian Andres Klode <julian.klode@canonical.com>2019-01-30 13:33:24 +0100
commit711cda2302b0dfe5d4ab0588b245ae4a97863e5b (patch)
tree1b9a017af0495a8479e284cbe1f4a4c45712a959
parent4200469bb5a14c4659285917ed30c46a0b15c286 (diff)
downloadapt-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).
-rw-r--r--apt-pkg/acquire-method.cc31
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)
{