Version in base suite: 3.10.5-1~deb13u1
Base version: postfix_3.10.5-1~deb13u1
Target version: postfix_3.10.11-0+deb13u1
Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/postfix/postfix_3.10.5-1~deb13u1.dsc
Target file: /srv/ftp-master.debian.org/policy/pool/main/p/postfix/postfix_3.10.11-0+deb13u1.dsc
HISTORY | 318 +++++++++++++++++++++++++
auxiliary/collate/collate.pl | 3
debian/NOTES | 2
debian/README.Debian | 57 ++--
debian/changelog | 106 ++++++++
debian/configure-instance.in | 8
debian/patches/debian-postfix-chroot-cmd.patch | 2
debian/patches/linux7.patch | 21 +
debian/patches/series | 1
debian/postfix.postinst | 2
debian/postfix.service | 8
debian/rules | 17 -
html/postconf.5.html | 15 -
html/smtpd.8.html | 2
makedefs | 64 ++++-
man/man5/postconf.5 | 16 -
man/man8/smtpd.8 | 2
proto/postconf.proto | 15 -
src/dns/dns_lookup.c | 7
src/dns/dns_strrecord.c | 2
src/global/dict_pgsql.c | 4
src/global/dsn_util.c | 2
src/global/mail_params.h | 6
src/global/mail_version.h | 4
src/global/pipe_command.c | 5
src/global/rfc2047_code.c | 6
src/global/smtp_stream.c | 8
src/milter/milter8.c | 4
src/postconf/postconf_edit.c | 6
src/smtp/smtp_proto.c | 2
src/smtp/smtp_tls_policy.c | 20 +
src/smtp/smtp_tlsrpt.c | 6
src/smtpd/smtpd.c | 27 ++
src/tls/tls_dane.c | 2
src/tls/tls_prng_file.c | 3
src/util/argv.c | 11
src/util/dict_cdb.c | 3
src/util/dict_cidr.c | 13 -
src/util/dict_db.c | 6
src/util/dict_pcre.c | 3
src/util/dict_sockmap.c | 3
src/util/midna_domain.c | 28 +-
src/util/msg_vstream.c | 1
src/util/netstring.c | 11
src/util/sys_defs.h | 19 -
src/util/vbuf_print.c | 29 +-
src/util/vstream.c | 20 +
src/util/vstream.h | 5
src/util/vstring.h | 2
49 files changed, 776 insertions(+), 151 deletions(-)
dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpnoj4vkud/postfix_3.10.5-1~deb13u1.dsc: no acceptable signature found
dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpnoj4vkud/postfix_3.10.11-0+deb13u1.dsc: no acceptable signature found
diff -Nru postfix-3.10.5/HISTORY postfix-3.10.11/HISTORY
--- postfix-3.10.5/HISTORY 2025-10-24 15:06:14.000000000 +0000
+++ postfix-3.10.11/HISTORY 2026-06-17 17:06:59.000000000 +0000
@@ -29208,3 +29208,321 @@
with "database X is older than source file Y". Files:
util/dict.c, util/dict_db.c, util/dict_dbm.c, util/dict_lmdb.c,
util/dict_sdbm.c.
+
+20251024
+
+ Logging: with "smtp_tls_enforce_sts_mx_patterns=yes" and
+ TLSRPT support enabled in a TLS policy plugin, the Postfix
+ SMTP client logs a warning when an MX hostname does not
+ match STS policy MX patterns; it logs a successful match
+ when verbose logging is enabled. File: smtp/smtp_tls_policy.c.
+
+20251027
+
+ Bugfix (defect introduced: Postfix 3.10, date: 20240902):
+ SMTP client null pointer crash when an STS policy plugin
+ sends no policy_string or no mx_pattern attributes. This
+ can happen only during tests with a fake STS plugin. File:
+ smtp/smtp_tlsrpt.c.
+
+20251028
+
+ Documentation: removed incorrect text from the parameter
+ description for smtp_cname_overrides_servername. File:
+ proto/postconf.proto.
+
+20251031
+
+ Bugfix (defect introduced: Postfix 3.10, date 20250117):
+ support for "TLS-Required: no" broke client-side TLS wrappermode
+ support, by downgrading a connection to TLS security level 'may'.
+ The solution is to change the downgrade level for wrappermode
+ connections to 'encrypt'. Rationale: by design, TLS can be
+ optional only for connections that use STARTTLS. The downgrade
+ to unauthenticated 'encrypt' allows a sender to avoid an email
+ delivery problem. Problem reported by Joshua Tyler Cochran.
+ File: smtp/smtp_tls_policy.c.
+
+20251120
+
+ Bugfix (defect introduced: Postfix 2.9, date: 20120307):
+ segfault with duplicate parameter name in "postconf -X" or
+ "postconf -#'. File: postconf/postconf_edit.c.
+
+20251205
+
+ Compatibility: recent Linux distributions have C compilers
+ with a built-in 'bool' type (size=1) that conflicts with
+ Postfix's bool (an alias for int, typically size=4). Postfix
+ 3.11 adopts the built-in bool type, but that change is too
+ large for the stable releases. Instead, the command "make
+ makefiles" will figure out how to make the compiler
+ backwards-compatible. File: makedefs.
+
+20251208
+
+ Improved Milter error handling for messages that arrive
+ over a long-lived SMTP connection, by changing the default
+ milter_default_action from "tempfail" to the new "shutdown"
+ action (i.e. disconnect the remote SMTP client).
+
+ The problem was that after a single Milter error, Postfix
+ could tempfail all messages that the client sends over a
+ long-lived connection, even if the Milter error was only
+ temporary. This problem was reported by Ankit Kulkarni.
+
+ Files: proto/postconf.proto global/mail_params.h milter/milter8.c.
+
+20260217
+
+ Bugfix: (defect introduced: Postfix 2.11): panic() after
+ recursive logging loop with "posttls-finger -v -v -v".
+ Reported by Geert Hendrickx, diagnosed by Viktor Dukhovni,
+ and fixed by Wietse. Files: util/vstream.[hc], util/msg_vstream.c.
+
+20260310
+
+ Bugfix (defect introduced: Postfix 3.0): buffer over-read
+ when Postfix is configured with an enhanced status code not
+ followed by other text. For example, "5.7.2" without text
+ after the three-number code in a remote server response,
+ in an access(5) table, header or body checks, or with
+ "$rbl_code $rbl_text" in rbl_reply_maps or default_rbl_reply.
+ Problem reported by Kamil Frankowicz. File: global/dsn_split.c.
+
+20260426
+
+ Portability: support for recent FreeBSD, NetBSD, and OpenBSD
+ versions. Brad Smith. Files: makedefs, util/sys_defs.h.
+
+20260501
+
+ Bugfix (defect introduced: Postfix 3.10): The RFC 2047
+ encoder for the sender "full name" could loop when a very
+ long full_name_encoding_charset value was configured in
+ main.cf. Found by Claude Opus 4.6. File: global/rfc2047_code.c.
+
+ Bugfix (defect introduced: Postfix 2.2, date 20041207):
+ When truncating a database file, the CDB client looked at
+ the file size from before requesting an exclusive lock on
+ a database file, instead of the file size after the exclusive
+ lock was granted. Found by Claude Opus 4.6. File:
+ util/dict_cdb.c.
+
+ Bugfix (defect introduced: Postfix alpha, date 19980309):
+ file descriptor leak after fork() failure. Found by Claude
+ Opus 4.6. File: global/pipe_command.c.
+
+ Mistakes in debug logging. Found by Claude Opus 4.6. Files:
+ dns/dns_lookup.c, util/dict_cidr.c, tls/tls_prng_file.c.
+
+ Unchecked null pointer results after an out-of-memory
+ condition in a library dependency. Found by Claude Opus
+ 4.6. Files: util/dict_pcre.c, util/midna_domain.c,
+ global/dict_pgsql.c.
+
+ Missing or incomplete guards for ssize_t or int overflow,
+ found by Claude Opus 4.6. Files: util/argv.c, util/netstring.c,
+ util/vbuf_print.c.
+
+ Cleanup: log a fatal error instead of dereferencing a null
+ pointer after a first/next cursor initialization failure.
+ Fedor Vorobev. File: util/dict_db.c.
+
+20260507
+
+ Fix for 'uninitialized value' error. Viktor Dukhovni. File:
+ auxiliary/collate/collate.pl.
+
+20260508
+
+ Claude AI finding: signed integer overshift (util/vstring.h).
+ Brought to our attention by Robert Sayre.
+
+20260513
+
+ Bitrot: builds with musl libc were using the obsolete
+ NO_SNPRINTF code path in vbuf_print.c. File: util/sys_defs.h.
+
+20260514
+
+ Bitrot: the obsolete NO_SNPRINTF code path in vbuf_print.c
+ wasn't updated for Claude Code findings. File: util/vbuf_print.c.
+
+20250515
+
+ Portability: The __MAXINT__(T) macro, to determine the
+ maximal signed value for objects of type T, was using
+ implementation-defined behavior (shift one bit into the
+ sign position). This works today but may break later.
+ Reported by Kamil Frankowicz. File: util/sys_defs.h.
+
+20260524
+
+ Bugfix (defect introduced: Postfix 3.1, date 20150607):
+ null pointer read and heap data overread in the Postfix
+ SMTP client's smtp_dns_reply_filter. Problem reported by
+ TristanInSec, found with ASAN. Also reported by other people.
+ Reproduction and real-world impact researched by Wietse.
+ File: dns/dns_strrecord.c.
+
+ This is a different problem than the one that was introduced
+ later in Postfix 3.6.
+
+ The root cause is a missing 'break' statement after the
+ code that converts a TLSA record to string.
+
+ Reproduction:
+ =============
+
+ The problem happens when smtp_dns_reply_filter is configured
+ (this is disabled by default); the Postfix SMTP client is
+ configured to use opportunistic or mandatory DANE authentication
+ (this is disabled by default); the destination domain
+ publishes a TLSA record that is empty or shorter than 20
+ bytes; and the OS is configured to use a resolver that
+ passes such a TLSA record. For example, a zero-length TLSA
+ record is blocked by BIND, Google DNS, OpenDNS, and by
+ configurations that use systemd-resolved (the default on
+ many LINUX systems); it is passed by Cloudflare, Quad9 DNS,
+ and unbound, as long as these resolvers are used without
+ systemd-resolved.
+
+ Impact statement:
+ =================
+
+ SMTP client termination with a null pointer read crash when
+ the TLSA record length is zero; or an SMTP client data
+ overread (or rarely, SMTP client termination with a read
+ segfault crash) when 0 < record length < 20 bytes. The
+ overread content is not disclosed.
+
+ The impact of SMTP client crashes is easily overstated.
+ That said, crashes must be eliminated regardless of their
+ impact.
+
+ On systems that deliver fewer than one message per minute,
+ an SMTP client crash can result in a delay of up to one
+ minute for email delivery to other destination domains. On
+ systems with a larger traffic volume, the impact of a null
+ pointer or other segfault crash on deliveries to other
+ destination domains is minor because Postfix reuses SMTP
+ client processes and replaces a failed process within seconds
+ (self-healing); the practical impact is believed to be no
+ worse than that of an uncooperative receiver that tarpits
+ SMTP connections from Postfix to one or more destination
+ domains under their control (by replying within Postfix
+ SMTP client read time limits which are several minutes by
+ default).
+
+20260529
+
+ Robustness: the Postfix SMTP server will no longer receive
+ (and discard) an unlimited amount of text while receiving
+ a long SMTP command line. Problem introduced: Postfix 2.9,
+ date: 20110205; reported by Michael Wollner (Ibonok). Under
+ high load conditions, the amount of text was already limited
+ by a 10-second deadline to receive an SMTP command. File:
+ global/smtp_stream.c.
+
+ Robustness: with the above change the Postfix SMTP client
+ will no longer receive (and discard) an unlimited amount
+ of text while receiving a long SMTP response line.
+
+ Robustness: do not receive (and discard) unlimited amounts
+ of data with BDAT commands. Problem introduced: Postfix
+ 3.4, date: 20180825; found during code maintenance. File:
+ smtpd/smtpd.c.
+
+ Impact statement:
+ =================
+
+ Postfix should not receive and discard unlimited amounts
+ of input in SMTP commands, but fixing that will not
+ fundamentally change the situation.
+
+ By design, any SMTP client can force a server to receive
+ (and discard) an unlimited amount of text. For example,
+ an attacker can repeatedly send messages that are a little
+ under the server's message size limit and abort each
+ transaction a before reaching the message end. When sending
+ a message with the "DATA" command, an attacker would
+ disconnect instead of sending The default action when a Milter (mail filter) response is
unavailable (for example, bad Postfix configuration or Milter
@@ -7380,11 +7380,20 @@
The current default action is "shutdown", i.e. disconnect the
+SMTP client. With the old "tempfail" default, Postfix could tempfail
+all messages that the client sends over a long-lived connection,
+even if a Milter failure is only temporary. This feature is available in Postfix 2.3 and later.
When DNS CNAME records are validated with secure DNS lookups -(smtp_dns_support_level = dnssec), they are always allowed to -override the above servername (Postfix 2.11 and later).
-This feature is available in Postfix 2.2.9 and later.
diff -Nru postfix-3.10.5/html/smtpd.8.html postfix-3.10.11/html/smtpd.8.html --- postfix-3.10.5/html/smtpd.8.html 2025-10-23 20:05:16.000000000 +0000 +++ postfix-3.10.11/html/smtpd.8.html 2026-06-17 17:13:38.000000000 +0000 @@ -264,7 +264,7 @@ sions for communication with a Milter application; prior to Postfix 2.6 the default protocol is 2. - milter_default_action (tempfail) + milter_default_action (see 'postconf -d milter_default_action' output) The default action when a Milter (mail filter) response is unavailable (for example, bad Postfix configuration or Milter failure). diff -Nru postfix-3.10.5/makedefs postfix-3.10.11/makedefs --- postfix-3.10.5/makedefs 2025-02-17 17:41:56.000000000 +0000 +++ postfix-3.10.11/makedefs 2026-05-01 20:09:28.000000000 +0000 @@ -351,6 +351,24 @@ : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} : ${PLUGIN_LD="${CC} -shared"} ;; + FreeBSD.15*) SYSTYPE=FREEBSD15 + : ${CC=cc} + : ${SHLIB_SUFFIX=.so} + : ${SHLIB_CFLAGS=-fPIC} + : ${SHLIB_LD="${CC} -shared"' -Wl,-soname,${LIB}'} + : ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'} + : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} + : ${PLUGIN_LD="${CC} -shared"} + ;; + FreeBSD.16*) SYSTYPE=FREEBSD16 + : ${CC=cc} + : ${SHLIB_SUFFIX=.so} + : ${SHLIB_CFLAGS=-fPIC} + : ${SHLIB_LD="${CC} -shared"' -Wl,-soname,${LIB}'} + : ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'} + : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} + : ${PLUGIN_LD="${CC} -shared"} + ;; DragonFly.*) SYSTYPE=DRAGONFLY ;; OpenBSD.2*) SYSTYPE=OPENBSD2 @@ -386,9 +404,18 @@ : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} : ${PLUGIN_LD="${CC} -shared"} ;; + OpenBSD.8*) SYSTYPE=OPENBSD8 + : ${CC=cc} + : ${SHLIB_SUFFIX=.so.1.0} + : ${SHLIB_CFLAGS=-fPIC} + : ${SHLIB_LD="${CC} -shared"' -Wl,-soname,${LIB}'} + : ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'} + : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} + : ${PLUGIN_LD="${CC} -shared"} + ;; ekkoBSD.1*) SYSTYPE=EKKOBSD1 ;; - NetBSD.1*) SYSTYPE=NETBSD1 + NetBSD.1.*) SYSTYPE=NETBSD1 ;; NetBSD.2*) SYSTYPE=NETBSD2 ;; @@ -438,6 +465,22 @@ : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} : ${PLUGIN_LD="${CC-gcc} -shared"} ;; + NetBSD.11*) SYSTYPE=NETBSD11 + : ${SHLIB_SUFFIX=.so} + : ${SHLIB_CFLAGS=-fPIC} + : ${SHLIB_LD="${CC-gcc} -shared"' -Wl,-soname,${LIB}'} + : ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'} + : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} + : ${PLUGIN_LD="${CC-gcc} -shared"} + ;; + NetBSD.12*) SYSTYPE=NETBSD12 + : ${SHLIB_SUFFIX=.so} + : ${SHLIB_CFLAGS=-fPIC} + : ${SHLIB_LD="${CC-gcc} -shared"' -Wl,-soname,${LIB}'} + : ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'} + : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"} + : ${PLUGIN_LD="${CC-gcc} -shared"} + ;; BSD/OS.2*) SYSTYPE=BSDI2 ;; BSD/OS.3*) SYSTYPE=BSDI3 @@ -1235,6 +1278,25 @@ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ -Wunused -Wno-missing-braces -fno-common'} +# C23 introduces a built-in type 'bool' (size 1) which breaks past Postfix +# practice where 'bool' is an alias for 'int' (typically, size 4). +# Fortunately, -std=gnu17 works with both gcc and clang. +cat >makedefs.test.c <<'EOF' +/* This appears in mail_params.h */ +typedef int bool; +EOF + +if eval ${CC} ${CCARGS} -c makedefs.test.c >/dev/null 2>&1 +then + : No further action needed. +elif eval ${CC} -std=gnu17 ${CCARGS} -c makedefs.test.c >/dev/null 2>&1 +then + CCARGS="-std=gnu17 $CCARGS" +else + error 'Please specify "CC=..." or "CCARGS=..." option to disable C23 bool' +fi +rm -f makedefs.test.[co] + # Extract map type names from -DHAS_XXX compiler options. We avoid # problems with tr(1) range syntax by using enumerations instead, # and we don't try to figure out which awk versions have tolower(). diff -Nru postfix-3.10.5/man/man5/postconf.5 postfix-3.10.11/man/man5/postconf.5 --- postfix-3.10.5/man/man5/postconf.5 2025-10-26 22:52:23.000000000 +0000 +++ postfix-3.10.11/man/man5/postconf.5 2026-02-18 19:20:01.000000000 +0000 @@ -4496,7 +4496,7 @@ for a list of available macro names and their meanings. .PP This feature is available in Postfix 2.3 and later. -.SH milter_default_action (default: tempfail) +.SH milter_default_action (default: see 'postconf \-d milter_default_action' output) The default action when a Milter (mail filter) response is unavailable (for example, bad Postfix configuration or Milter failure). Specify one of the following: @@ -4511,12 +4511,22 @@ Reject all further commands in this session with a temporary status code. .br +.IP "shutdown" +Close the SMTP connection after sending a 421 +SMTP reply. Available in Postfix 3.11, 3.10.8, 3.9.9, 3.8.15, 3.7.20, +and later. +.br .IP "quarantine" Like "accept", but freeze the message in the "hold" queue. Available with Postfix 2.6 and later. .br .br .PP +The current default action is "shutdown", i.e. disconnect the +SMTP client. With the old "tempfail" default, Postfix could tempfail +all messages that the client sends over a long\-lived connection, +even if a Milter failure is only temporary. +.PP This feature is available in Postfix 2.3 and later. .SH milter_end_of_data_macros (default: see "postconf \-d" output) The macros that are sent to Milter (mail filter) applications @@ -7136,10 +7146,6 @@ password file lookups more predictable. This is the default setting as of Postfix 2.3. .PP -When DNS CNAME records are validated with secure DNS lookups -(smtp_dns_support_level = dnssec), they are always allowed to -override the above servername (Postfix 2.11 and later). -.PP This feature is available in Postfix 2.2.9 and later. .SH smtp_connect_timeout (default: 30s) The Postfix SMTP client time limit for completing a TCP connection, or diff -Nru postfix-3.10.5/man/man8/smtpd.8 postfix-3.10.11/man/man8/smtpd.8 --- postfix-3.10.5/man/man8/smtpd.8 2025-10-23 20:05:15.000000000 +0000 +++ postfix-3.10.11/man/man8/smtpd.8 2026-06-17 17:13:38.000000000 +0000 @@ -259,7 +259,7 @@ The mail filter protocol version and optional protocol extensions for communication with a Milter application; prior to Postfix 2.6 the default protocol is 2. -.IP "\fBmilter_default_action (tempfail)\fR" +.IP "\fBmilter_default_action (see 'postconf -d milter_default_action' output)\fR" The default action when a Milter (mail filter) response is unavailable (for example, bad Postfix configuration or Milter failure). diff -Nru postfix-3.10.5/proto/postconf.proto postfix-3.10.11/proto/postconf.proto --- postfix-3.10.5/proto/postconf.proto 2025-10-24 14:41:15.000000000 +0000 +++ postfix-3.10.11/proto/postconf.proto 2026-02-18 16:51:40.000000000 +0000 @@ -11398,10 +11398,6 @@ password file lookups more predictable. This is the default setting as of Postfix 2.3. -When DNS CNAME records are validated with secure DNS lookups -(smtp_dns_support_level = dnssec), they are always allowed to -override the above servername (Postfix 2.11 and later).
-This feature is available in Postfix 2.2.9 and later.
%PARAM lmtp_cname_overrides_servername yes @@ -12278,7 +12274,7 @@This feature is available in Postfix 2.3 and later.
-%PARAM milter_default_action tempfail +%PARAM milter_default_action see 'postconf -d milter_default_action' outputThe default action when a Milter (mail filter) response is unavailable (for example, bad Postfix configuration or Milter @@ -12295,11 +12291,20 @@
The current default action is "shutdown", i.e. disconnect the +SMTP client. With the old "tempfail" default, Postfix could tempfail +all messages that the client sends over a long-lived connection, +even if a Milter failure is only temporary.
+This feature is available in Postfix 2.3 and later.
%PARAM milter_connect_timeout 30s diff -Nru postfix-3.10.5/src/dns/dns_lookup.c postfix-3.10.11/src/dns/dns_lookup.c --- postfix-3.10.5/src/dns/dns_lookup.c 2024-10-10 22:15:18.000000000 +0000 +++ postfix-3.10.11/src/dns/dns_lookup.c 2026-05-01 20:02:52.000000000 +0000 @@ -834,14 +834,15 @@ for (src = pos, dst = (unsigned char *) ltemp; src < pos + fixed->length; /* */ ) { frag_len = *src++; - if (msg_verbose) - msg_info("frag_len=%d text=\"%.*s\"", - (int) frag_len, (int) frag_len, (char *) src); + /* 202604 Claude: move debug logging after the frag_len check. */ if (frag_len > reply->end - src || frag_len >= ((unsigned char *) ltemp + sizeof(ltemp)) - dst) { msg_warn("extract_answer: bad TXT string length: %d", frag_len); return (DNS_RETRY); } + if (msg_verbose) + msg_info("frag_len=%d text=\"%.*s\"", + (int) frag_len, (int) frag_len, (char *) src); while (frag_len-- > 0) { ch = *src++; *dst++ = (ISPRINT(ch) ? ch : ' '); diff -Nru postfix-3.10.5/src/dns/dns_strrecord.c postfix-3.10.11/src/dns/dns_strrecord.c --- postfix-3.10.5/src/dns/dns_strrecord.c 2023-02-13 20:58:00.000000000 +0000 +++ postfix-3.10.11/src/dns/dns_strrecord.c 2026-06-17 17:06:59.000000000 +0000 @@ -99,6 +99,8 @@ } else { vstring_sprintf_append(buf, "[truncated record]"); } + /* 202605 Missing break found by TristanInSec using ASAN. */ + break; /* * We use the SOA record TTL to determine the negative reply TTL. We diff -Nru postfix-3.10.5/src/global/dict_pgsql.c postfix-3.10.11/src/global/dict_pgsql.c --- postfix-3.10.5/src/global/dict_pgsql.c 2025-02-07 15:32:55.000000000 +0000 +++ postfix-3.10.11/src/global/dict_pgsql.c 2026-05-01 20:02:52.000000000 +0000 @@ -574,8 +574,10 @@ dict_pgsql->password); } if (host->db == NULL || PQstatus(host->db) != CONNECTION_OK) { + /* 202604 Claude: don't call PQerrorMessage(NULL). */ msg_warn("connect to pgsql server %s: %s", - host->hostname, PQerrorMessage(host->db)); + host->hostname, host->db ? PQerrorMessage(host->db) : + "PQconnectdb or PQsetdbLogin failed"); plpgsql_down_host(host, dict_pgsql->retry_interval); return; } diff -Nru postfix-3.10.5/src/global/dsn_util.c postfix-3.10.11/src/global/dsn_util.c --- postfix-3.10.5/src/global/dsn_util.c 2006-01-08 01:28:37.000000000 +0000 +++ postfix-3.10.11/src/global/dsn_util.c 2026-05-01 20:06:13.000000000 +0000 @@ -154,7 +154,7 @@ if ((len = dsn_valid(cp)) > 0) { strncpy(dp->dsn.data, cp, len); dp->dsn.data[len] = 0; - cp += len + 1; + cp += len; } else if ((len = dsn_valid(def_dsn)) > 0) { strncpy(dp->dsn.data, def_dsn, len); dp->dsn.data[len] = 0; diff -Nru postfix-3.10.5/src/global/mail_params.h postfix-3.10.11/src/global/mail_params.h --- postfix-3.10.5/src/global/mail_params.h 2025-10-24 14:41:15.000000000 +0000 +++ postfix-3.10.11/src/global/mail_params.h 2026-02-18 16:40:51.000000000 +0000 @@ -3516,7 +3516,7 @@ extern char *var_cleanup_milters; #define VAR_MILT_DEF_ACTION "milter_default_action" -#define DEF_MILT_DEF_ACTION "tempfail" +#define DEF_MILT_DEF_ACTION "shutdown" extern char *var_milt_def_action; #define VAR_MILT_CONN_MACROS "milter_connect_macros" @@ -3571,10 +3571,6 @@ #define DEF_MILT_PROTOCOL "6" extern char *var_milt_protocol; -#define VAR_MILT_DEF_ACTION "milter_default_action" -#define DEF_MILT_DEF_ACTION "tempfail" -extern char *var_milt_def_action; - #define VAR_MILT_DAEMON_NAME "milter_macro_daemon_name" #define DEF_MILT_DAEMON_NAME "$" VAR_MYHOSTNAME extern char *var_milt_daemon_name; diff -Nru postfix-3.10.5/src/global/mail_version.h postfix-3.10.11/src/global/mail_version.h --- postfix-3.10.5/src/global/mail_version.h 2025-10-26 22:48:02.000000000 +0000 +++ postfix-3.10.11/src/global/mail_version.h 2026-06-17 17:07:33.000000000 +0000 @@ -20,8 +20,8 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20251026" -#define MAIL_VERSION_NUMBER "3.10.5" +#define MAIL_RELEASE_DATE "20260617" +#define MAIL_VERSION_NUMBER "3.10.11" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff -Nru postfix-3.10.5/src/global/pipe_command.c postfix-3.10.11/src/global/pipe_command.c --- postfix-3.10.5/src/global/pipe_command.c 2014-12-25 16:47:18.000000000 +0000 +++ postfix-3.10.11/src/global/pipe_command.c 2026-05-01 20:02:52.000000000 +0000 @@ -460,6 +460,11 @@ msg_warn("fork: %m"); dsb_unix(why, "4.3.0", sys_exits_detail(EX_OSERR)->text, "Delivery failed: %m"); + /* 202604 Claude: close pipes for the child and parent paths. */ + close(cmd_in_pipe[0]); + close(cmd_in_pipe[1]); + close(cmd_out_pipe[0]); + close(cmd_out_pipe[1]); return (PIPE_STAT_DEFER); /* diff -Nru postfix-3.10.5/src/global/rfc2047_code.c postfix-3.10.11/src/global/rfc2047_code.c --- postfix-3.10.5/src/global/rfc2047_code.c 2025-01-05 17:35:43.000000000 +0000 +++ postfix-3.10.11/src/global/rfc2047_code.c 2026-05-01 20:02:52.000000000 +0000 @@ -274,6 +274,12 @@ msg_warn("%s: encoder called with empty charset name", myname); return (0); } + /* 202604 Claude: avoid 'space_left' underflow. */ + if (strlen(charset) > ENC_WORD_MAX_LEN / 2) { + msg_warn("%s: unreasonable charset name: '%.100s'", + myname, charset); + return (0); + } for (cp = (const unsigned char *) charset; (ch = *cp) != 0; cp++) { if (!RFC2047_ALLOWED_TOKEN_CHAR(ch)) { msg_warn("%s: invalid character: 0x%x in charset name: '%s'", diff -Nru postfix-3.10.5/src/global/smtp_stream.c postfix-3.10.11/src/global/smtp_stream.c --- postfix-3.10.5/src/global/smtp_stream.c 2024-01-12 18:39:59.000000000 +0000 +++ postfix-3.10.11/src/global/smtp_stream.c 2026-06-17 17:06:59.000000000 +0000 @@ -457,8 +457,12 @@ && vstream_feof(stream) == 0 && vstream_ferror(stream) == 0) while ((next_char = VSTREAM_GETC(stream)) != VSTREAM_EOF && next_char != '\n') - /* void */ ; - + if (--bound <= 0) { + msg_warn("disabling input from %s", VSTREAM_PATH(stream)); + vstream_fpurge(stream, VSTREAM_PURGE_READ); + shutdown(vstream_fileno(stream), SHUT_RD); + break; + } return (last_char); } diff -Nru postfix-3.10.5/src/milter/milter8.c postfix-3.10.11/src/milter/milter8.c --- postfix-3.10.5/src/milter/milter8.c 2025-01-07 22:25:43.000000000 +0000 +++ postfix-3.10.11/src/milter/milter8.c 2026-02-18 16:40:51.000000000 +0000 @@ -523,6 +523,8 @@ } if (strcasecmp(milter->def_action, "accept") == 0) { reply = 0; + } else if (strcasecmp(milter->def_action, "shutdown") == 0) { + reply = "421 4.3.5 Server configuration problem - try again later"; } else if (strcasecmp(milter->def_action, "quarantine") == 0) { reply = "Hdefault_action"; } else { @@ -557,6 +559,8 @@ reply = "550 5.5.0 Service unavailable"; } else if (strcasecmp(milter->def_action, "tempfail") == 0) { reply = "451 4.7.1 Service unavailable - try again later"; + } else if (strcasecmp(milter->def_action, "shutdown") == 0) { + reply = "421 4.7.1 Service unavailable - try again later"; } else if (strcasecmp(milter->def_action, "quarantine") == 0) { reply = "Hdefault_action"; } else { diff -Nru postfix-3.10.5/src/postconf/postconf_edit.c postfix-3.10.11/src/postconf/postconf_edit.c --- postfix-3.10.5/src/postconf/postconf_edit.c 2025-10-23 20:03:49.000000000 +0000 +++ postfix-3.10.11/src/postconf/postconf_edit.c 2025-11-25 17:20:32.000000000 +0000 @@ -209,8 +209,10 @@ msg_panic("pcf_edit_main: unknown mode %d", mode); } if ((cvalue = htable_find(table, pattern)) != 0) { - msg_warn("ignoring earlier request: '%s = %s'", - pattern, cvalue->value); + if (edit_value && cvalue->value + && strcmp(edit_value, cvalue->value) != 0) + msg_warn("ignoring earlier request: '%s = %s'", + pattern, cvalue->value); htable_delete(table, pattern, myfree); } cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue)); diff -Nru postfix-3.10.5/src/smtp/smtp_proto.c postfix-3.10.11/src/smtp/smtp_proto.c --- postfix-3.10.5/src/smtp/smtp_proto.c 2025-10-23 18:17:45.000000000 +0000 +++ postfix-3.10.11/src/smtp/smtp_proto.c 2026-06-17 17:06:59.000000000 +0000 @@ -1867,7 +1867,7 @@ vstring_sprintf_append(next_command, " ORCPT=%s", vstring_str(session->scratch)); } else { - xtext_quote(session->scratch, orcpt_type_addr, "="); + xtext_quote(session->scratch, orcpt_type_addr, "+="); vstring_sprintf_append(next_command, " ORCPT=%s", vstring_str(session->scratch)); } diff -Nru postfix-3.10.5/src/smtp/smtp_tls_policy.c postfix-3.10.11/src/smtp/smtp_tls_policy.c --- postfix-3.10.5/src/smtp/smtp_tls_policy.c 2025-10-24 14:41:15.000000000 +0000 +++ postfix-3.10.11/src/smtp/smtp_tls_policy.c 2025-11-25 19:31:07.000000000 +0000 @@ -187,9 +187,16 @@ } else #endif aname = name; - for (pattp = tls->ext_mx_host_patterns->argv; *pattp; pattp++) - if (match_sts_mx_host_pattern(*pattp, aname)) + for (pattp = tls->ext_mx_host_patterns->argv; *pattp; pattp++) { + if (match_sts_mx_host_pattern(*pattp, aname)) { + if (msg_verbose) + msg_info("MX name '%s' matches STS MX pattern for '%s'", + aname, tls->ext_policy_domain ? tls->ext_policy_domain : ""); return (1); + } + } + msg_warn("MX name '%s' does not match STS MX pattern for '%s'", + aname, tls->ext_policy_domain ? tls->ext_policy_domain : ""); return (0); } /* No applicable policy name patterns. */ @@ -725,8 +732,13 @@ if (STATE_TLS_NOT_REQUIRED(iter->parent)) { if (msg_verbose) msg_info("%s: no tls policy lookup", __func__); - if (tls->level > TLS_LEV_MAY) - tls->level = TLS_LEV_MAY; + if (var_smtp_tls_wrappermode) { + if (tls->level > TLS_LEV_ENCRYPT) + tls->level = TLS_LEV_ENCRYPT; + } else { + if (tls->level > TLS_LEV_MAY) + tls->level = TLS_LEV_MAY; + } } else if (tls_policy) { tls_policy_lookup(tls, &site_level, dest, "next-hop destination"); } else if (tls_per_site) { diff -Nru postfix-3.10.5/src/smtp/smtp_tlsrpt.c postfix-3.10.11/src/smtp/smtp_tlsrpt.c --- postfix-3.10.5/src/smtp/smtp_tlsrpt.c 2024-10-10 22:15:24.000000000 +0000 +++ postfix-3.10.11/src/smtp/smtp_tlsrpt.c 2025-11-25 19:23:32.000000000 +0000 @@ -306,13 +306,15 @@ if (tls->ext_policy_type == 0) msg_panic("smtp_tlsrpt_set_ext_policy: no policy type"); +#define ARGV_OR_NULL(ap) ((ap) ? (ap)->argv : 0) + switch (policy_type_val = convert_tlsrpt_policy_type(tls->ext_policy_type)) { case TLSRPT_POLICY_STS: trw_set_tls_policy(state->tlsrpt, policy_type_val, - (const char *const *) tls->ext_policy_strings->argv, + (const char *const *) ARGV_OR_NULL(tls->ext_policy_strings), tls->ext_policy_domain, - (const char *const *) tls->ext_mx_host_patterns->argv); + (const char *const *) ARGV_OR_NULL(tls->ext_mx_host_patterns)); break; case TLSRPT_NO_POLICY_FOUND: smtp_tlsrpt_set_no_policy(state); diff -Nru postfix-3.10.5/src/smtpd/smtpd.c postfix-3.10.11/src/smtpd/smtpd.c --- postfix-3.10.5/src/smtpd/smtpd.c 2025-10-23 16:45:51.000000000 +0000 +++ postfix-3.10.11/src/smtpd/smtpd.c 2026-06-17 17:13:38.000000000 +0000 @@ -233,7 +233,7 @@ /* The mail filter protocol version and optional protocol extensions /* for communication with a Milter application; prior to Postfix 2.6 /* the default protocol is 2. -/* .IP "\fBmilter_default_action (tempfail)\fR" +/* .IP "\fBmilter_default_action (see 'postconf -d milter_default_action' output)\fR" /* The default action when a Milter (mail filter) response is /* unavailable (for example, bad Postfix configuration or Milter /* failure). @@ -3958,6 +3958,21 @@ off_t len; /* + * Skip inputs below 1.5 times the message size limit, staying in sync + * with the remote SMTP client. Otherwise, force a negative chunk_size + * value to disable reading and discarding input here, and to force a + * "lost connection" condition upon a later read operation. + */ + if (ENFORCING_SIZE_LIMIT(var_message_limit) + && state->act_size / 1.5 > var_message_limit - chunk_size / 1.5) { + chunk_size = -1; + } else if (state->act_size > OFF_T_MAX - chunk_size) { + state->act_size = OFF_T_MAX; + } else { + state->act_size += chunk_size; + } + + /* * Read and discard content from the remote SMTP client. TODO: drop the * connection in case of overload. */ @@ -3975,6 +3990,16 @@ va_end(ap); /* + * Force a "lost connection" condition upon the next read operation. + */ + if (chunk_size < 0) { + msg_warn("%s: too much BDAT content -- disabling further input from %s", + state->queue_id ? state->queue_id : "NOQUEUE", + state->namaddr); + shutdown(vstream_fileno(state->client), SHUT_RD); + } + + /* * Reset state, or drop subsequent BDAT payloads until BDAT LAST or RSET. */ if (final_chunk) diff -Nru postfix-3.10.5/src/tls/tls_dane.c postfix-3.10.11/src/tls/tls_dane.c --- postfix-3.10.5/src/tls/tls_dane.c 2024-10-10 22:15:24.000000000 +0000 +++ postfix-3.10.11/src/tls/tls_dane.c 2026-06-17 17:06:59.000000000 +0000 @@ -518,7 +518,7 @@ q, a, r, rr->type); /* Drop truncated records */ - if ((dlen = rr->data_len - 3) < 0) { + if ((dlen = rr->data_len - 3) <= 0) { msg_warn("%s%s%s: truncated TLSA RR length == %u", q, a, r, (unsigned) rr->data_len); return (0); diff -Nru postfix-3.10.5/src/tls/tls_prng_file.c postfix-3.10.11/src/tls/tls_prng_file.c --- postfix-3.10.5/src/tls/tls_prng_file.c 2014-12-07 01:35:33.000000000 +0000 +++ postfix-3.10.11/src/tls/tls_prng_file.c 2026-05-01 20:02:52.000000000 +0000 @@ -132,7 +132,8 @@ RAND_seed(buffer, count); } if (msg_verbose) - msg_info("read %ld bytes from entropy file %s: %m", + /* 202604 Claude: remove '%m' from non-error logging. */ + msg_info("read %ld bytes from entropy file %s", (long) (len - to_read), fh->name); return (len - to_read); } diff -Nru postfix-3.10.5/src/util/argv.c postfix-3.10.11/src/util/argv.c --- postfix-3.10.5/src/util/argv.c 2025-01-17 21:21:02.000000000 +0000 +++ postfix-3.10.11/src/util/argv.c 2026-05-01 20:02:52.000000000 +0000 @@ -203,6 +203,9 @@ argvp = (ARGV *) mymalloc(sizeof(*argvp)); argvp->len = 0; sane_len = (len < 2 ? 2 : len); + /* 202604 Claude: avoid overflowing sane_len + 1 */ + if (sane_len > SSIZE_MAX - 1) + msg_panic("argv_alloc: array length overflow"); argvp->argv = (char **) mymalloc((sane_len + 1) * sizeof(char *)); argvp->len = sane_len; argvp->argc = 0; @@ -261,6 +264,9 @@ { ssize_t new_len; + /* 202604 Claude: avoid overflowing (new_len + 1) * sizeof(char *). */ + if (argvp->len > SSIZE_MAX / (2 * sizeof(char *)) - 1) + msg_panic("argv_extend: array length overflow"); new_len = argvp->len * 2; argvp->argv = (char **) myrealloc((void *) argvp->argv, (new_len + 1) * sizeof(char *)); @@ -404,9 +410,10 @@ ssize_t pos; /* - * Sanity check. + * Sanity check. 202604 Claude: avoid expression 'first + how_many'. */ - if (first < 0 || how_many < 0 || first + how_many > argvp->argc) + if (first < 0 || how_many < 0 || first > argvp->argc + || how_many > argvp->argc - first) msg_panic("argv_delete bad range: (start=%ld count=%ld)", (long) first, (long) how_many); diff -Nru postfix-3.10.5/src/util/dict_cdb.c postfix-3.10.11/src/util/dict_cdb.c --- postfix-3.10.5/src/util/dict_cdb.c 2025-01-09 21:32:35.000000000 +0000 +++ postfix-3.10.11/src/util/dict_cdb.c 2026-05-01 20:02:52.000000000 +0000 @@ -456,7 +456,8 @@ } #ifndef NO_FTRUNCATE - if (st0.st_size) + /* 202604 Claude: use the post-myflock() fstat result. */ + if (st1.st_size) ftruncate(fd, 0); #endif diff -Nru postfix-3.10.5/src/util/dict_cidr.c postfix-3.10.11/src/util/dict_cidr.c --- postfix-3.10.5/src/util/dict_cidr.c 2023-04-16 20:41:47.000000000 +0000 +++ postfix-3.10.11/src/util/dict_cidr.c 2026-05-01 20:02:52.000000000 +0000 @@ -237,11 +237,14 @@ rule->lineno = lineno; if (msg_verbose) { - if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes, - hostaddr.buf, sizeof(hostaddr.buf)) == 0) - msg_fatal("inet_ntop: %m"); - msg_info("dict_cidr_open: add %s/%d %s", - hostaddr.buf, cidr_info.mask_shift, rule->value); + /* 202604 Claude: ENDIF has no address pattern. */ + if (cidr_info.op != CIDR_MATCH_OP_ENDIF) { + if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes, + hostaddr.buf, sizeof(hostaddr.buf)) == 0) + msg_fatal("inet_ntop: %m"); + msg_info("dict_cidr_open: add %s/%d %s", + hostaddr.buf, cidr_info.mask_shift, rule->value); + } } return (rule); } diff -Nru postfix-3.10.5/src/util/dict_db.c postfix-3.10.11/src/util/dict_db.c --- postfix-3.10.5/src/util/dict_db.c 2025-10-23 20:00:35.000000000 +0000 +++ postfix-3.10.11/src/util/dict_db.c 2026-05-01 20:03:50.000000000 +0000 @@ -446,8 +446,10 @@ */ switch (function) { case DICT_SEQ_FUN_FIRST: - if (dict_db->cursor == 0) - DICT_DB_CURSOR(db, &(dict_db->cursor)); + if (dict_db->cursor == 0 + && (status = DICT_DB_CURSOR(db, &(dict_db->cursor))) != 0) + msg_fatal("error [%d] initializing cursor for %s: %m", + status, dict_db->dict.name); db_function = DB_FIRST; break; case DICT_SEQ_FUN_NEXT: diff -Nru postfix-3.10.5/src/util/dict_pcre.c postfix-3.10.11/src/util/dict_pcre.c --- postfix-3.10.5/src/util/dict_pcre.c 2023-04-16 20:42:29.000000000 +0000 +++ postfix-3.10.11/src/util/dict_pcre.c 2026-05-01 20:02:52.000000000 +0000 @@ -728,6 +728,9 @@ } engine->match_data = pcre2_match_data_create_from_pattern( engine->pattern, (void *) 0); + /* 202604 Claude: handle error result. */ + if (engine->match_data == 0) + msg_fatal("out of memory in pcre2_match_data_create_from_pattern()"); #endif return (1); } diff -Nru postfix-3.10.5/src/util/dict_sockmap.c postfix-3.10.11/src/util/dict_sockmap.c --- postfix-3.10.5/src/util/dict_sockmap.c 2025-01-07 22:30:28.000000000 +0000 +++ postfix-3.10.11/src/util/dict_sockmap.c 2026-05-01 20:02:52.000000000 +0000 @@ -254,7 +254,8 @@ reply_payload = split_at(STR(dp->rdwr_buf), ' '); if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_OK) == 0) { dict->error = 0; - return (reply_payload); + /* 202604 Claude: don't return NULL with dict->error==0. */ + return (reply_payload ? reply_payload : ""); } else if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_NOTFOUND) == 0) { dict->error = 0; return (0); diff -Nru postfix-3.10.5/src/util/midna_domain.c postfix-3.10.11/src/util/midna_domain.c --- postfix-3.10.5/src/util/midna_domain.c 2024-11-21 17:49:05.000000000 +0000 +++ postfix-3.10.11/src/util/midna_domain.c 2026-05-01 20:02:52.000000000 +0000 @@ -189,11 +189,13 @@ */ idna = uidna_openUTS46(midna_domain_transitional ? UIDNA_DEFAULT : UIDNA_NONTRANSITIONAL_TO_ASCII, &error); - anl = uidna_nameToASCII_UTF8(idna, - name, strlen(name), - buf, sizeof(buf) - 1, - &info, - &error); + /* 202604 Claude: avoid null deref after uidna_openUTS46() failure. */ + if (idna && U_SUCCESS(error)) + anl = uidna_nameToASCII_UTF8(idna, + name, strlen(name), + buf, sizeof(buf) - 1, + &info, + &error); uidna_close(idna); /* @@ -203,7 +205,7 @@ * "fake" A-labels, as required by UTS 46 section 4.1, but we rely on * valid_hostname() on the output side just to be sure. */ - if (U_SUCCESS(error) && info.errors == 0 && anl > 0) { + if (idna && U_SUCCESS(error) && info.errors == 0 && anl > 0) { buf[anl] = 0; /* XXX */ if (!valid_hostname(buf, DONT_GRIPE)) { msg_warn("%s: Problem translating domain \"%.100s\" to ASCII form: %s", @@ -243,11 +245,13 @@ */ idna = uidna_openUTS46(midna_domain_transitional ? UIDNA_DEFAULT : UIDNA_NONTRANSITIONAL_TO_UNICODE, &error); - anl = uidna_nameToUnicodeUTF8(idna, - name, strlen(name), - buf, sizeof(buf) - 1, - &info, - &error); + /* 202604 Claude: avoid null deref after uidna_openUTS46() failure. */ + if (idna && U_SUCCESS(error)) + anl = uidna_nameToUnicodeUTF8(idna, + name, strlen(name), + buf, sizeof(buf) - 1, + &info, + &error); uidna_close(idna); /* @@ -256,7 +260,7 @@ * other invalid forms that are not covered in UTS 46, section 4.1). We * rely on midna_domain_to_ascii() to validate the output. */ - if (U_SUCCESS(error) && info.errors == 0 && anl > 0) { + if (idna && U_SUCCESS(error) && info.errors == 0 && anl > 0) { buf[anl] = 0; /* XXX */ if (midna_domain_to_ascii(buf) == 0) return (0); diff -Nru postfix-3.10.5/src/util/msg_vstream.c postfix-3.10.11/src/util/msg_vstream.c --- postfix-3.10.5/src/util/msg_vstream.c 2006-06-15 18:07:16.000000000 +0000 +++ postfix-3.10.11/src/util/msg_vstream.c 2026-02-18 16:52:29.000000000 +0000 @@ -80,6 +80,7 @@ msg_tag = name; msg_stream = vp; + vstream_no_debug(vp); if (first_call) { first_call = 0; msg_output(msg_vstream_print); diff -Nru postfix-3.10.5/src/util/netstring.c postfix-3.10.11/src/util/netstring.c --- postfix-3.10.5/src/util/netstring.c 2025-01-07 22:30:28.000000000 +0000 +++ postfix-3.10.11/src/util/netstring.c 2026-05-01 20:02:52.000000000 +0000 @@ -305,14 +305,17 @@ VA_COPY(ap2, ap); /* - * Figure out the total result size. + * Figure out the total result size. 202604 Claude: move the wrap-around + * guard inside the loop. */ - for (total = 0; (data = va_arg(ap, char *)) != 0; total += data_len) + for (total = 0; (data = va_arg(ap, char *)) != 0; /* see below */ ) { if ((data_len = va_arg(ap, ssize_t)) < 0) msg_panic("%s: bad data length %ld", myname, (long) data_len); + if (data_len > SSIZE_T_MAX - total) + msg_panic("%s: total length overflow", myname); + total += data_len; + } va_end(ap); - if (total < 0) - msg_panic("%s: bad total length %ld", myname, (long) total); if (msg_verbose > 1) msg_info("%s: write total length %ld", myname, (long) total); diff -Nru postfix-3.10.5/src/util/sys_defs.h postfix-3.10.11/src/util/sys_defs.h --- postfix-3.10.5/src/util/sys_defs.h 2025-01-03 18:19:26.000000000 +0000 +++ postfix-3.10.11/src/util/sys_defs.h 2026-05-15 19:34:03.000000000 +0000 @@ -31,14 +31,15 @@ || defined(FREEBSD5) || defined(FREEBSD6) || defined(FREEBSD7) \ || defined(FREEBSD8) || defined(FREEBSD9) || defined(FREEBSD10) \ || defined(FREEBSD11) || defined(FREEBSD12) || defined(FREEBSD13) \ - || defined(FREEBSD14) \ + || defined(FREEBSD14) || defined(FREEBSD15) || defined(FREEBSD16) \ || defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \ || defined(OPENBSD2) || defined(OPENBSD3) || defined(OPENBSD4) \ || defined(OPENBSD5) || defined(OPENBSD6) || defined(OPENBSD7) \ + || defined(OPENBSD8) \ || defined(NETBSD1) || defined(NETBSD2) || defined(NETBSD3) \ || defined(NETBSD4) || defined(NETBSD5) || defined(NETBSD6) \ || defined(NETBSD7) | defined(NETBSD8) || defined(NETBSD9) \ - || defined(NETBSD10) \ + || defined(NETBSD10) || defined(NETBSD11) || defined(NETBSD12) \ || defined(EKKOBSD1) || defined(DRAGONFLY) #define SUPPORTED #include