Hi,

Two notes on this bug, for the CVEs I could settle.

CVE-2026-100890, opendmarc_spf_ipv6_explode()
Upstream fixed this in commit a1fea0b ("libopendmarc: fix NULL-pointer
deref in opendmarc_spf_ipv6_explode()", May 2025). It is on the develop
branch but not on master or in any release tag, so 1.4.2 lacks it. The
commit is attached as a format-patch and applies without changes on top of
the patch series of 1.4.2-5.1, 1.4.2-5 and 1.4.2-2.

I did not reproduce the crash. I compiled the function before and after
with ASan and UBSan in a small harness and ran 5 well-formed IPv6 addresses
through it on those three versions. The eight chunks were identical and the
sanitizers reported nothing. One visible change: nstrs becomes 8 instead of
9 for those addresses, because the loop now breaks before the final
decrement. nstrs bounds the loop in opendmarc_spf_ipv6_cidr_populate() over
strs[8], so 8 looks like the correct value, but I did not trace that
function further. I did not build the full package or run its tests.

CVE-2026-101014, opendmarc_util_cleanup()
The CVE's off-by-one is already fixed in Debian by cleanup-buflen.patch,
which the changelog adds in 1.4.1.1-2. The patched check (strlen >= buflen)
is in the applied sources of 1.4.2-2, 1.4.2-5 and 1.4.2-5.1. Upstream made
the same change much later, in 2c4c094. Tracker suggestion:

CVE-2026-101014
- opendmarc 1.4.1.1-2 (bug #1149876)

Bullseye's 1.4.0~beta1+dfsg-6+deb11u1 has no such patch in debian/patches,
so it probably remains open there; I did not read that version's code.

I have not assessed the other CVEs in this bug.

Regards,
Sumit Verma
From a1fea0b405f7c69fbe13a0f1cec38413f678a0b3 Mon Sep 17 00:00:00 2001
From: Mikel Olasagasti Uranga <[email protected]>
Date: Fri, 2 May 2025 23:07:50 +0200
Subject: [PATCH] =?UTF-8?q?libopendmarc:=20fix=20NULL=E2=80=93pointer=20de?=
 =?UTF-8?q?ref=20in=20opendmarc=5Fspf=5Fipv6=5Fexplode()?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When parsing IPv6 literals the loop in opendmarc_spf_ipv6_explode()
advances the working pointer with

        cp = ep + 1;

unconditionally.  For the last 16-bit chunk of the address
‛strchr(cp, ':')’ returns NULL, so the assignment produces the invalid
pointer (NULL + 1).  On the following iteration strchr() immediately
reads from that address and the milter crashes with SIGSEGV.

The bug is exposed whenever OpenDMARC evaluates an “ip6:” SPF mechanism
whose prefix lacks a trailing colon, e.g.

    ip6:2001:db8::/32

Typical trigger path:
  * Postfix submission (SASL) from ::1
  * OpenDMARC runs SPF check against the domain’s own record
  * ::1 is matched against the record above
  * opendmarc_spf_ipv6_explode() crashes

Guard the assignment by bailing out of the loop when no further ‘:’
is present, thereby preserving the valid value of ‘cp’.

Closes: #274
Signed-off-by: Mikel Olasagasti Uranga <[email protected]>
---
 libopendmarc/opendmarc_spf.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/libopendmarc/opendmarc_spf.c b/libopendmarc/opendmarc_spf.c
index e015183..c02ba6f 100644
--- a/libopendmarc/opendmarc_spf.c
+++ b/libopendmarc/opendmarc_spf.c
@@ -745,7 +745,15 @@ opendmarc_spf_ipv6_explode(char *str, TXT_ARY_T *ap)
 			}
 			i+= 1;
 		}
-		cp = ep+1;
+		/*
+		* If strchr() did not find another ':' we have reached the
+		* last chunk of the IPv6 literal.  Advancing the pointer
+		* when ep is NULL would yield (NULL + 1) and lead to a
+		* segmentation fault on the next iteration.
+		*/
+		if (ep == NULL)
+			break;
+		cp = ep + 1;
 	}
 	ap->nstrs = 8 - i;
 	return 0;
-- 
2.53.0

Reply via email to