]> granicus.if.org Git - pdns/commitdiff
dnsdist: Fix potential pointer wrap-around on 32 bits
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 10 Aug 2017 12:14:34 +0000 (14:14 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 21 Aug 2017 07:58:58 +0000 (09:58 +0200)
This can lead to a DoS on 32 bits if a backend server sends a
crafted response and we happen to be working with a buffer allocated to
a very high virtual address.

Reported by Guido Vranken (many thanks!).

pdns/dnsdist-ecs.cc

index bab9e3fea4395ba46e25cf8ebb84e74fba01fa30..2a51d492b9f4210f1126fe5915e38cf0f1ca2818 100644 (file)
@@ -392,26 +392,29 @@ void handleEDNSClientSubnet(char* const packet, const size_t packetSize, const u
 static int removeEDNSOptionFromOptions(unsigned char* optionsStart, const uint16_t optionsLen, const uint16_t optionCodeToRemove, uint16_t* newOptionsLen)
 {
   unsigned char* p = optionsStart;
-  const unsigned char* end = p + optionsLen;
-  while ((p + 4) <= end) {
+  size_t pos = 0;
+  while ((pos + 4) <= optionsLen) {
     unsigned char* optionBegin = p;
     const uint16_t optionCode = 0x100*p[0] + p[1];
     p += sizeof(optionCode);
+    pos += sizeof(optionCode);
     const uint16_t optionLen = 0x100*p[0] + p[1];
     p += sizeof(optionLen);
-    if ((p + optionLen) > end) {
+    pos += sizeof(optionLen);
+    if ((pos + optionLen) > optionsLen) {
       return EINVAL;
     }
     if (optionCode == optionCodeToRemove) {
-      if (p + optionLen < end) {
+      if (pos + optionLen < optionsLen) {
         /* move remaining options over the removed one,
            if any */
-        memmove(optionBegin, p + optionLen, end - (p + optionLen));
+        memmove(optionBegin, p + optionLen, optionsLen - (pos + optionLen));
       }
       *newOptionsLen = optionsLen - (sizeof(optionCode) + sizeof(optionLen) + optionLen);
       return 0;
     }
     p += optionLen;
+    pos += optionLen;
   }
   return ENOENT;
 }