CVE-2017-12989: Loop with Unreachable Exit Condition ('Infinite Loop') (CWE-835)
value: The RESP parser in tcpdump before 4.9.2 could enter an infinite loop due to a bug in print-resp.c:resp_get_length().
CWE description: The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.
CVSS v3 base score: 7.5
Published: 2017-09-14T06:29Z
Repository: https://github.com/the-tcpdump-group/tcpdump
Language: Other
Files changed: print-resp.c, tests/TESTLIST, tests/resp_4_infiniteloop.out
Commit date: 2017-09-13 12:25:44 +0100
Commit message: CVE-2017-12989/RESP: Make sure resp_get_length() advances the pointer for invalid lengths.

Make sure that it always sends *endp before returning and that, for
invalid lengths where we don't like a character in the length string,
what it sets *endp to is past the character in question, so we don't
run the risk of infinitely looping (or doing something else random) if a
character in the length is invalid.

This fixes an infinite loop discovered by Forcepoint's security
researchers Otto Airamo & Antti Levomäki.

Add a test using the capture file supplied by the reporter(s).

Diff: diff --git a/print-resp.c b/print-resp.c
index 9d71e21dc..dee22d63a 100644
--- a/print-resp.c
+++ b/print-resp.c
@@ -479,12 +479,14 @@ resp_get_length(netdissect_options *ndo, register const u_char *bp, int len, con
         if (len == 0)
             goto trunc;
         ND_TCHECK(*bp);
         c = *bp;
         if (!(c >= '0' && c <= '9')) {
-            if (!saw_digit)
+            if (!saw_digit) {
+                bp++;
                 goto invalid;
+            }
             break;
         }
         c -= '0';
         if (result > (INT_MAX / 10)) {
             /* This will overflow an int when we multiply it by 10. */
@@ -508,19 +510,23 @@ resp_get_length(netdissect_options *ndo, register const u_char *bp, int len, con
      * OK, the next thing should be \r\n.
      */
     if (len == 0)
         goto trunc;
     ND_TCHECK(*bp);
-    if (*bp != '\r')
+    if (*bp != '\r') {
+        bp++;
         goto invalid;
+    }
     bp++;
     len--;
     if (len == 0)
         goto trunc;
     ND_TCHECK(*bp);
-    if (*bp != '\n')
+    if (*bp != '\n') {
+        bp++;
         goto invalid;
+    }
     bp++;
     len--;
     *endp = bp;
     if (neg) {
         /* -1 means "null", anything else is invalid */
@@ -529,10 +535,12 @@ resp_get_length(netdissect_options *ndo, register const u_char *bp, int len, con
         result = -1;
     }
     return (too_large ? -3 : result);
 
 trunc:
+    *endp = bp;
     return (-2);
 
 invalid:
+    *endp = bp;
     return (-5);
 }
diff --git a/tests/TESTLIST b/tests/TESTLIST
index e0f0bb146..ecf54f69b 100644
--- a/tests/TESTLIST
+++ b/tests/TESTLIST
@@ -466,10 +466,11 @@ tok2str-oobr-2		tok2str-oobr-2.pcap		tok2str-oobr-2.out	-vvv -e
 eigrp-tlv-oobr		eigrp-tlv-oobr.pcap		eigrp-tlv-oobr.out	-vvv -e
 zephyr-oobr		zephyr-oobr.pcap		zephyr-oobr.out		-vvv -e
 bgp-as-path-oobr	bgp-as-path-oobr.pcap		bgp-as-path-oobr.out	-vvv -e
 isakmp-no-none-np	isakmp-no-none-np.pcap		isakmp-no-none-np.out	-vvv -e
 telnet-iac-check-oobr	telnet-iac-check-oobr.pcap	telnet-iac-check-oobr.out	-vvv -e
+resp_4_infiniteloop	resp_4_infiniteloop.pcap	resp_4_infiniteloop.out	-vvv -e
 
 # RTP tests
 # fuzzed pcap
 rtp-seg-fault-1  rtp-seg-fault-1.pcap  rtp-seg-fault-1.out  -v -T rtp
 rtp-seg-fault-2  rtp-seg-fault-2.pcap  rtp-seg-fault-2.out  -v -T rtp
diff --git a/tests/resp_4_infiniteloop.out b/tests/resp_4_infiniteloop.out
new file mode 100644
index 000000000..396cb8b39
--- /dev/null
+++ b/tests/resp_4_infiniteloop.out
@@ -0,0 +1,2 @@
+00:50:56:b4:08:69 > 00:50:56:b4:4c:2a, ethertype IPv4 (0x0800), length 920: (tos 0x0, ttl 64, id 27576, offset 0, flags [DF], proto TCP (6), length 906)
+    172.16.8.77.33926 > 172.16.8.149.6379: Flags [P.], cksum 0xa129 (incorrect -> 0xaaa0), seq 3839414413:3839415267, ack 2526552240, win 229, options [nop,nop,TS val 2407226 ecr 24894817], length 854: RESP length negative and not -1 invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid "4" "EVAL" invalid invalid invalid invalid "GKMbNZq^@0" "stuubt.pack('<ivdMFG4294967245',^V ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''319', 2',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',', '-1494241318543828858')'L')N))'r')')~D')')E)')')')')')')')'l')')')')')'M-`'o')')'Pp)U)" invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid "1" [|RESP]
diff --git a/tests/resp_4_infiniteloop.pcap b/tests/resp_4_infiniteloop.pcap
new file mode 100644
index 000000000..98a79bfb6
Binary files /dev/null and b/tests/resp_4_infiniteloop.pcap differ

Vulnerable code:             if (!saw_digit)
    if (*bp != '\r')
    if (*bp != '\n')
Fixed code:             if (!saw_digit) {
                bp++;
            }
    if (*bp != '\r') {
        bp++;
    }
    if (*bp != '\n') {
        bp++;
    }
    *endp = bp;
    *endp = bp;
resp_4_infiniteloop	resp_4_infiniteloop.pcap	resp_4_infiniteloop.out	-vvv -e
00:50:56:b4:08:69 > 00:50:56:b4:4c:2a, ethertype IPv4 (0x0800), length 920: (tos 0x0, ttl 64, id 27576, offset 0, flags [DF], proto TCP (6), length 906)
    172.16.8.77.33926 > 172.16.8.149.6379: Flags [P.], cksum 0xa129 (incorrect -> 0xaaa0), seq 3839414413:3839415267, ack 2526552240, win 229, options [nop,nop,TS val 2407226 ecr 24894817], length 854: RESP length negative and not -1 invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid "4" "EVAL" invalid invalid invalid invalid "GKMbNZq^@0" "stuubt.pack('<ivdMFG4294967245',^V ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''319', 2',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',', '-1494241318543828858')'L')N))'r')')~D')')E)')')')')')')')'l')')')')')'M-`'o')')'Pp)U)" invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid invalid "1" [|RESP]