diff --git a/net/pdns-recursor/patches/300-cve-2022-27227.patch b/net/pdns-recursor/patches/300-cve-2022-27227.patch new file mode 100644 index 0000000000..4cc99510e7 --- /dev/null +++ b/net/pdns-recursor/patches/300-cve-2022-27227.patch @@ -0,0 +1,171 @@ +--- a/ixfr.cc ++++ b/ixfr.cc +@@ -123,7 +123,7 @@ vector, vector, vector > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr, ++vector, vector > > getIXFRDeltas(const ComboAddress& primary, const DNSName& zone, const DNSRecord& oursr, + const TSIGTriplet& tt, const ComboAddress* laddr, size_t maxReceivedBytes) + { + vector, vector > > ret; +@@ -137,7 +137,7 @@ vector, vector, vector, vector masterSOA = nullptr; ++ std::shared_ptr primarySOA = nullptr; + vector records; + size_t receivedBytes = 0; +- int8_t ixfrInProgress = -2; + std::string reply; + ++ enum transferStyle { Unknown, AXFR, IXFR } style = Unknown; ++ const unsigned int expectedSOAForAXFR = 2; ++ const unsigned int expectedSOAForIXFR = 3; ++ unsigned int primarySOACount = 0; ++ + for(;;) { +- // IXFR end +- if (ixfrInProgress >= 0) ++ // IXFR or AXFR style end reached? We don't want to process trailing data after the closing SOA ++ if (style == AXFR && primarySOACount == expectedSOAForAXFR) { ++ break; ++ } ++ else if (style == IXFR && primarySOACount == expectedSOAForIXFR) { + break; ++ } + + if(s.read((char*)&len, sizeof(len)) != sizeof(len)) + break; +@@ -191,7 +199,7 @@ vector, vector 0 && (maxReceivedBytes - receivedBytes) < (size_t) len) +- throw std::runtime_error("Reached the maximum number of received bytes in an IXFR delta for zone '"+zone.toLogString()+"' from master "+master.toStringWithPort()); ++ throw std::runtime_error("Reached the maximum number of received bytes in an IXFR delta for zone '"+zone.toLogString()+"' from primary "+primary.toStringWithPort()); + + reply.resize(len); + readn2(s.getHandle(), &reply.at(0), len); +@@ -199,7 +207,7 @@ vector, vector, vectorgetZoneRepresentation()<(r.first); + if (!sr) { +- throw std::runtime_error("Error getting the content of the first SOA record of the IXFR answer for zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort()+"'"); ++ throw std::runtime_error("Error getting the content of the first SOA record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"'"); + } + + if(sr->d_st.serial == std::dynamic_pointer_cast(oursr.d_content)->d_st.serial) { + // we are up to date + return ret; + } +- masterSOA = sr; ++ primarySOA = sr; ++ ++primarySOACount; + } else if (r.first.d_type == QType::SOA) { + auto sr = getRR(r.first); + if (!sr) { +- throw std::runtime_error("Error getting the content of SOA record of IXFR answer for zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort()+"'"); ++ throw std::runtime_error("Error getting the content of SOA record of IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"'"); + } + +- // we hit the last SOA record +- // IXFR is considered to be done if we hit the last SOA record twice +- if (masterSOA->d_st.serial == sr->d_st.serial) { +- ixfrInProgress++; ++ // we hit a marker SOA record ++ if (primarySOA->d_st.serial == sr->d_st.serial) { ++ ++primarySOACount; ++ } ++ } ++ // When we see the 2nd record, we can decide what the style is ++ if (records.size() == 1 && style == Unknown) { ++ if (r.first.d_type != QType::SOA) { ++ // Non-empty AXFR style has a non-SOA record following the first SOA ++ style = AXFR; ++ } ++ else if (primarySOACount == expectedSOAForAXFR) { ++ // Empty zone AXFR style: start SOA is immediately followed by end marker SOA ++ style = AXFR; ++ } ++ else { ++ // IXFR has a 2nd SOA (with different serial) following the first ++ style = IXFR; + } + } + +@@ -245,7 +268,7 @@ vector, vector, vector