Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:42.3:Update
pdns-recursor
CVE-2018-14626-rec-4.0.8.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2018-14626-rec-4.0.8.patch of Package pdns-recursor
diff -ru pdns-recursor-4.0.8.orig/pdns_recursor.cc pdns-recursor-4.0.8/pdns_recursor.cc --- pdns-recursor-4.0.8.orig/pdns_recursor.cc 2017-12-11 11:38:52.000000000 +0100 +++ pdns-recursor-4.0.8/pdns_recursor.cc 2018-10-09 17:14:58.052450425 +0200 @@ -1134,7 +1134,7 @@ if(sendmsg(dc->d_socket, &msgh, 0) < 0 && g_logCommonErrors) L<<Logger::Warning<<"Sending UDP reply to client "<<dc->d_remote.toStringWithPort()<<" failed with: "<<strerror(errno)<<endl; if(!SyncRes::s_nopacketcache && !variableAnswer && !sr.wasVariable() ) { - t_packetCache->insertResponsePacket(dc->d_tag, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_query, + t_packetCache->insertResponsePacket(dc->d_tag, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass, dc->d_query, string((const char*)&*packet.begin(), packet.size()), g_now.tv_sec, pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl : diff -ru pdns-recursor-4.0.8.orig/recpacketcache.cc pdns-recursor-4.0.8/recpacketcache.cc --- pdns-recursor-4.0.8.orig/recpacketcache.cc 2017-12-11 11:38:52.000000000 +0100 +++ pdns-recursor-4.0.8/recpacketcache.cc 2018-10-09 17:08:20.176479437 +0200 @@ -42,17 +42,59 @@ return count; } +static bool queryHeaderMatches(const std::string& cachedQuery, const std::string& query) +{ + if (cachedQuery.size() != query.size()) { + return false; + } + + return (cachedQuery.compare(/* skip the ID */ 2, sizeof(dnsheader) - 2, query, 2, sizeof(dnsheader) - 2) == 0); +} + +bool RecursorPacketCache::queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname, uint16_t ecsBegin, uint16_t ecsEnd) +{ + if (!queryHeaderMatches(cachedQuery, query)) { + return false; + } + + size_t pos = sizeof(dnsheader) + qname.wirelength(); + + if (ecsBegin != 0 && ecsBegin >= pos && ecsEnd > ecsBegin) { + if (cachedQuery.compare(pos, ecsBegin - pos, query, pos, ecsBegin - pos) != 0) { + return false; + } + + if (cachedQuery.compare(ecsEnd, cachedQuery.size() - ecsEnd, query, ecsEnd, query.size() - ecsEnd) != 0) { + return false; + } + } + else { + if (cachedQuery.compare(pos, cachedQuery.size() - pos, query, pos, query.size() - pos) != 0) { + return false; + } + } + + return true; +} + // one day this function could be really fast by doing only a case insensitive compare -static bool qrMatch(const std::string& query, const std::string& response) +bool RecursorPacketCache::qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, uint16_t ecsBegin, uint16_t ecsEnd) { - uint16_t rqtype, rqclass, qqtype, qqclass; - DNSName queryname(query.c_str(), query.length(), sizeof(dnsheader), false, &qqtype, &qqclass, 0); - DNSName respname(response.c_str(), response.length(), sizeof(dnsheader), false, &rqtype, &rqclass, 0); - // this ignores checking on the EDNS subnet flags! - return queryname==respname && rqtype == qqtype && rqclass == qqclass; + uint16_t qqtype, qqclass; + DNSName queryname(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, &qqtype, &qqclass, 0); + // this ignores checking on the EDNS subnet flags! + if (qqtype != iter->d_type || qqclass != iter->d_class || queryname != iter->d_name) { + return false; + } + + if (iter->d_ecsBegin != ecsBegin || iter->d_ecsEnd != ecsEnd) { + return false; + } + + return queryMatches(iter->d_query, queryPacket, queryname, ecsBegin, ecsEnd); } -uint32_t RecursorPacketCache::canHashPacket(const std::string& origPacket) +uint32_t RecursorPacketCache::canHashPacket(const std::string& origPacket, uint16_t* ecsBegin, uint16_t* ecsEnd) { // return 42; // should still work if you do this! uint32_t ret=0; @@ -68,6 +110,10 @@ struct dnsheader* dh = (struct dnsheader*)origPacket.c_str(); const char* skipBegin = p; const char* skipEnd = p; + if (ecsBegin != nullptr && ecsEnd != nullptr) { + *ecsBegin = 0; + *ecsEnd = 0; + } /* we need at least 1 (final empty label) + 2 (QTYPE) + 2 (QCLASS) + OPT root label (1), type (2), class (2) and ttl (4) + the OPT RR rdlen (2) @@ -82,6 +128,10 @@ if (res == 0) { skipBegin = optionBegin; skipEnd = optionBegin + optionLen; + if (ecsBegin != nullptr && ecsEnd != nullptr) { + *ecsBegin = optionBegin - origPacket.c_str(); + *ecsEnd = *ecsBegin + optionLen; + } } } if (skipBegin > p) { @@ -96,15 +146,11 @@ } bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, - std::string* responsePacket, uint32_t* age) -{ - return getResponsePacket(tag, queryPacket, now, responsePacket, age, nullptr); -} - -bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage) { - uint32_t h = canHashPacket(queryPacket); + uint16_t ecsBegin = 0; + uint16_t ecsEnd = 0; + uint32_t h = canHashPacket(queryPacket, &ecsBegin, &ecsEnd); auto& idx = d_packetCache.get<HashTag>(); auto range = idx.equal_range(tie(tag,h)); @@ -115,8 +161,9 @@ for(auto iter = range.first ; iter != range.second ; ++ iter) { // the possibility is VERY real that we get hits that are not right - birthday paradox - if(!qrMatch(queryPacket, iter->d_packet)) + if(!qrMatch(iter, queryPacket, ecsBegin, ecsEnd)) { continue; + } if((uint32_t)now < iter->d_ttd) { // it is right, it is fresh! *age = now - iter->d_creation; *responsePacket = iter->d_packet; @@ -153,27 +200,28 @@ } -void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttl) +void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage) { - insertResponsePacket(tag, qname, qtype, queryPacket, responsePacket, now, ttl, nullptr); -} - -void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage) -{ - auto qhash = canHashPacket(queryPacket); + uint16_t ecsBegin = 0; + uint16_t ecsEnd = 0; + auto qhash = canHashPacket(queryPacket, &ecsBegin, &ecsEnd); auto& idx = d_packetCache.get<HashTag>(); auto range = idx.equal_range(tie(tag,qhash)); auto iter = range.first; for( ; iter != range.second ; ++iter) { - if(iter->d_type != qtype) + if(iter->d_type != qtype || iter->d_class != qclass) { continue; + } // this only happens on insert which is relatively rare and does not need to be super fast DNSName respname(iter->d_packet.c_str(), iter->d_packet.length(), sizeof(dnsheader), false, 0, 0, 0); if(qname != respname) continue; moveCacheItemToBack(d_packetCache, iter); iter->d_packet = responsePacket; + iter->d_query = queryPacket; + iter->d_ecsBegin = ecsBegin; + iter->d_ecsEnd = ecsEnd; iter->d_ttd = now + ttl; iter->d_creation = now; #ifdef HAVE_PROTOBUF @@ -188,9 +236,13 @@ if(iter == range.second) { // nothing to refresh struct Entry e; e.d_packet = responsePacket; + e.d_query = queryPacket; e.d_name = qname; e.d_qhash = qhash; e.d_type = qtype; + e.d_class = qclass; + e.d_ecsBegin = ecsBegin; + e.d_ecsEnd = ecsEnd; e.d_ttd = now+ttl; e.d_creation = now; e.d_tag = tag; diff -ru pdns-recursor-4.0.8.orig/recpacketcache.hh pdns-recursor-4.0.8/recpacketcache.hh --- pdns-recursor-4.0.8.orig/recpacketcache.hh 2017-12-11 11:38:52.000000000 +0100 +++ pdns-recursor-4.0.8/recpacketcache.hh 2018-10-09 17:14:58.052450425 +0200 @@ -50,10 +50,8 @@ { public: RecursorPacketCache(); - bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age); - void insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttd); bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage); - void insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttd, const RecProtoBufMessage* protobufMessage); + void insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttd, const RecProtoBufMessage* protobufMessage); void doPruneTo(unsigned int maxSize=250000); uint64_t doDump(int fd); int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false); @@ -72,12 +70,16 @@ mutable uint32_t d_creation; // so we can 'age' our packets DNSName d_name; uint16_t d_type; + uint16_t d_class; mutable std::string d_packet; // "I know what I am doing" + mutable std::string d_query; #ifdef HAVE_PROTOBUF mutable RecProtoBufMessage d_protobufMessage; #endif uint32_t d_qhash; uint32_t d_tag; + mutable uint16_t d_ecsBegin; + mutable uint16_t d_ecsEnd; inline bool operator<(const struct Entry& rhs) const; uint32_t getTTD() const @@ -85,7 +87,7 @@ return d_ttd; } }; - uint32_t canHashPacket(const std::string& origPacket); + typedef multi_index_container< Entry, indexed_by < @@ -96,6 +98,11 @@ > packetCache_t; packetCache_t d_packetCache; + +public: + static bool queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname, uint16_t ecsBegin, uint16_t ecsEnd); + static bool qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, uint16_t ecsBegin, uint16_t ecsEnd); + static uint32_t canHashPacket(const std::string& origPacket, uint16_t* ecsBegin, uint16_t* ecsEnd); }; #endif diff -ru pdns-recursor-4.0.8.orig/test-recpacketcache_cc.cc pdns-recursor-4.0.8/test-recpacketcache_cc.cc --- pdns-recursor-4.0.8.orig/test-recpacketcache_cc.cc 2017-12-11 11:38:52.000000000 +0100 +++ pdns-recursor-4.0.8/test-recpacketcache_cc.cc 2018-10-09 17:14:58.052450425 +0200 @@ -33,19 +33,19 @@ pw.commit(); string rpacket((const char*)&packet[0], packet.size()); - rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600); + rpc.insertResponsePacket(0,qname, QType::A, QClass::IN, qpacket, rpacket, time(0), 3600, nullptr); BOOST_CHECK_EQUAL(rpc.size(), 1); rpc.doPruneTo(0); BOOST_CHECK_EQUAL(rpc.size(), 0); - rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600); + rpc.insertResponsePacket(0,qname, QType::A, QClass::IN, qpacket, rpacket, time(0), 3600, nullptr); BOOST_CHECK_EQUAL(rpc.size(), 1); rpc.doWipePacketCache(qname); BOOST_CHECK_EQUAL(rpc.size(), 0); - rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600); + rpc.insertResponsePacket(0,qname, QType::A, QClass::IN, qpacket, rpacket, time(0), 3600, nullptr); uint32_t age=0; string fpacket; - bool found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age); + bool found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age, nullptr); BOOST_CHECK_EQUAL(found, 1); BOOST_CHECK_EQUAL(fpacket, rpacket); @@ -57,7 +57,7 @@ pw2.getHeader()->qr=false; pw2.getHeader()->id=random(); qpacket.assign((const char*)&packet[0], packet.size()); - found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age); + found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age, nullptr); BOOST_CHECK_EQUAL(found, 0); rpc.doWipePacketCache(DNSName("com"), 0xffff, true);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor