Vulnerability: InspIRCd before 2.0.7 allows remote attackers to cause a denial of service (infinite loop).
Vulnerability ID: CVE-2012-6697
CWE: CWE-399
Severity score: 2.9
Project: https://github.com/inspircd/inspircd
Published: 2017-04-13
File: src/dns.cpp
Commit message: Fixed infinite loop cauesd by invalid dns packets
Commit author: Adam

Vulnerable version (before fix):
 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) 		 */ 		case DNS_QUERY_CNAME: 		case DNS_QUERY_PTR: 			o = 0; 			q = 0; 			while (q == 0 && i < length && o + 256 < 1023) DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) 					i = ntohs(ptr);  					/* check that highest two bits are set. if not, we've been had */ 					if (!(i & DN_COMP_BITMASK)) 						return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");  					/* mask away the two highest bits. */ 					i &= ~DN_COMP_BITMASK;  					/* and decrease length by 12 bytes. */ 					i =- 12; 				} 				else 				{ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) 				} 			} 			res[o] = 0; 		break; 		case DNS_QUERY_AAAA: 			if (rr.rdlength != sizeof(struct in6_addr))

Fixed version (after fix):
 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) 		 */ 		case DNS_QUERY_CNAME: 		case DNS_QUERY_PTR: 		{ 			unsigned short lowest_pos = length; 			o = 0; 			q = 0; 			while (q == 0 && i < length && o + 256 < 1023) DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) 					i = ntohs(ptr);  					/* check that highest two bits are set. if not, we've been had */ 					if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK) 						return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");  					/* mask away the two highest bits. */ 					i &= ~DN_COMP_BITMASK;  					/* and decrease length by 12 bytes. */ 					i -= 12;  					if (i >= lowest_pos) 						return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer"); 					lowest_pos = i; 				} 				else 				{ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) 				} 			} 			res[o] = 0; 		} 		break; 		case DNS_QUERY_AAAA: 			if (rr.rdlength != sizeof(struct in6_addr))

Patch:
patch: @@ -800,6 +800,8 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
 		 */
 		case DNS_QUERY_CNAME:
 		case DNS_QUERY_PTR:
+		{
+			unsigned short lowest_pos = length;
 			o = 0;
 			q = 0;
 			while (q == 0 && i < length && o + 256 < 1023)
@@ -812,14 +814,18 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
 					i = ntohs(ptr);
 
 					/* check that highest two bits are set. if not, we've been had */
-					if (!(i & DN_COMP_BITMASK))
+					if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK)
 						return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
 
 					/* mask away the two highest bits. */
 					i &= ~DN_COMP_BITMASK;
 
 					/* and decrease length by 12 bytes. */
-					i =- 12;
+					i -= 12;
+
+					if (i >= lowest_pos)
+						return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer");
+					lowest_pos = i;
 				}
 				else
 				{
@@ -843,6 +849,7 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
 				}
 			}
 			res[o] = 0;
+		}
 		break;
 		case DNS_QUERY_AAAA:
 			if (rr.rdlength != sizeof(struct in6_addr))
path: src/dns.cpp