From bd910269addb1e7f8a343765c8531f20a6b99498 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Mon, 11 Apr 2016 11:14:41 +0200 Subject: [PATCH] Throw if DNSName would overflow when asked to read type/class Otherwise, the caller has to check the consumed size to know if the type and class he asked for have been read, while it clearly expected them to be present. Fix a crash in dnsdist ECS parsing found by american fuzzy lop. --- pdns/dnscrypt.cc | 2 ++ pdns/dnsdist-ecs.cc | 3 +++ pdns/dnsname.cc | 14 ++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/pdns/dnscrypt.cc b/pdns/dnscrypt.cc index fd280e93b..636c02498 100644 --- a/pdns/dnscrypt.cc +++ b/pdns/dnscrypt.cc @@ -180,6 +180,8 @@ void DnsCryptContext::parsePlaintextQuery(const char * packet, uint16_t packetSi unsigned int consumed; uint16_t qtype, qclass; DNSName qname(packet, packetSize, sizeof(dnsheader), false, &qtype, &qclass, &consumed); + if ((packetSize - sizeof(dnsheader)) < (consumed + sizeof(qtype) + sizeof(qclass))) + return; if (qtype != QType::TXT || qclass != QClass::IN) return; diff --git a/pdns/dnsdist-ecs.cc b/pdns/dnsdist-ecs.cc index 0bc87ae85..8f29ade2c 100644 --- a/pdns/dnsdist-ecs.cc +++ b/pdns/dnsdist-ecs.cc @@ -197,6 +197,9 @@ static int getEDNSOptionsStart(char* packet, const size_t offset, const size_t l unsigned int consumed; DNSName aname(packet, len, pos, true, &qtype, &qclass, &consumed); + if ((len - pos) < (consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) + return ENOENT; + pos += consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE; if(qtype != QType::OPT || (len - pos) < (DNS_TTL_SIZE + DNS_RDLENGTH_SIZE)) return ENOENT; diff --git a/pdns/dnsname.cc b/pdns/dnsname.cc index de30cf67f..55849c5a9 100644 --- a/pdns/dnsname.cc +++ b/pdns/dnsname.cc @@ -111,13 +111,19 @@ void DNSName::packetParser(const char* qpos, int len, int offset, bool uncompres d_storage.append(1, (char)0); // we just parsed the root if(consumed) *consumed = pos - opos - offset; - if(qtype && pos + labellen + 2 <= end) + if(qtype) { + if (pos + labellen + 2 > end) { + throw std::range_error("Trying to read qtype past the end of the buffer ("+std::to_string((pos - opos) + labellen + 2)+ " > "+std::to_string(len)+")"); + } *qtype=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1); - + } pos+=2; - if(qclass && pos + labellen + 2 <= end) + if(qclass) { + if (pos + labellen + 2 > end) { + throw std::range_error("Trying to read qclass past the end of the buffer ("+std::to_string((pos - opos) + labellen + 2)+ " > "+std::to_string(len)+")"); + } *qclass=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1); - + } } std::string DNSName::toString(const std::string& separator, const bool trailing) const -- 2.40.0