SPF: harden against crafted DNS responses
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 10 Oct 2023 11:45:27 +0000 (12:45 +0100)
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Sat, 14 Oct 2023 21:50:37 +0000 (23:50 +0200)
(cherry picked from commit 4f07f38374f8662c318699fb30432273ffcfe0d3)

src/src/spf.c

index db6eea3a823a84be992f0bd28852a43859bed387..1981d81b630963506231c3b038bfa6ad7e5af0f7 100644 (file)
@@ -120,6 +120,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
     switch(rr_type)
       {
       case T_MX:
+       if (rr->size < 2) continue;
        s += 2; /* skip the MX precedence field */
       case T_PTR:
        {
@@ -135,6 +136,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
        gstring * g = NULL;
        uschar chunk_len;
 
+       if (rr->size < 1+6) continue;           /* min for version str */
        if (strncmpic(rr->data+1, US SPF_VER_STR, 6) != 0)
          {
          HDEBUG(D_host_lookup) debug_printf("not an spf record: %.*s\n",
@@ -142,9 +144,12 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
          continue;
          }
 
-       for (int off = 0; off < rr->size; off += chunk_len)
+       /* require 1 byte for the chunk_len */
+       for (int off = 0; off < rr->size - 1; off += chunk_len)
          {
-         if (!(chunk_len = s[off++])) break;
+         if (  !(chunk_len = s[off++])
+            || rr->size < off + chunk_len      /* ignore bogus size chunks */
+            ) break;
          g = string_catn(g, s+off, chunk_len);
          }
        if (!g)