From 09b3b35712edba043dae563d0cb42cd0ebb32b38 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Thu, 10 Aug 2017 14:14:34 +0200 Subject: [PATCH] dnsdist: Fix potential pointer wrap-around on 32 bits 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 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pdns/dnsdist-ecs.cc b/pdns/dnsdist-ecs.cc index bab9e3fea..2a51d492b 100644 --- a/pdns/dnsdist-ecs.cc +++ b/pdns/dnsdist-ecs.cc @@ -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; } -- 2.40.0