summaryrefslogtreecommitdiff
path: root/apt-pkg
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 /apt-pkg
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).
Diffstat (limited to 'apt-pkg')
-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)
{