[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1065562: bookworm-pu: package postfix/3.7.10-0+deb12u1



Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: postfix@packages.debian.org
Control: affects -1 + src:postfix

[ Reason ]
Standard postfix post-release update

[ Impact ]
They will still have the bugs that are fixed by this update.

[ Tests ]
There is an autopkgtest, which passes locally.  I also have the package
in production on one server and it is running fine.

[ Risks ]
Risk is low.  Changes are relatively minor and are as released by
upstream, which has an excellent track record for such things.

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]
  * 3.7.11
    - Bugfix (defect introduced: Postfix 2.3, date 20051222): the
      Dovecot auth client did not reset the 'reason' from  a
      previous Dovecot auth service response, before parsing the
      next Dovecot auth server response in the same SMTP session.
      Reported by Stephan Bosch, File: xsasl/xsasl_dovecot_server.c.
    - Cleanup: Postfix SMTP server response with an empty
      authentication failure reason. File: smtpd/smtpd_sasl_glue.c.
    - Bugfix (defect introduced: Postfix 3.1, date: 20151128):
      "postqueue -j" produced broken JSON when escaping a control
      character as \uXXXX. Found during code maintenance. File:
      postqueue/showq_json.c.
    - Cleanup: posttls-finger certificate match expectations for
      all TLS security levels, including warnings for levels that
      don't implement certificate matching. Viktor Dukhovni.
      File: posttls-finger.c.
    - Bugfix (defect introduced: Postfix 2.3): after prepending
      a message header with a Postfix access table PREPEND action,
      a Milter request to delete or update an existing header
      could have no effect, or it could target the wrong instance
      of an existing header. Root cause: the fix dated 20141018
      for the Postfix Milter client was incomplete. The client
      did correctly hide the first, Postfix-generated, Received:
      header when sending message header information to a Milter
      with the smfi_header() application callback function, but
      it was still hiding the first header (instead of the first
      Received: header) when handling requests from a Milter to
      delete or update an existing header. Problem report by
      Carlos Velasco. This change was verified to have no effect
      on requests from a Milter to add or insert a header. File:
      cleanup/cleanup_milter.c.
    - Workaround: tlsmgr logfile spam. Some OS lies under load:
      it says that a socket is readable, then it says that the
      socket has unread data, and then it says that read returns
      EOF, causing Postfix to spam the log with a warning message.
      File: tlsmgr/tlsmgr.c.
    - Bugfix (defect introduced: Postfix 3.4): the SMTP server's
      BDAT command handler could be tricked to read $message_size_limit
      bytes into memory. Found during code maintenance. File:
      smtpd/smtpd.c.
    - Performance: eliminate worst-case behavior where the queue
      manager defers delivery to all destinations over a specific
      delivery transport, after only a single delivery agent
      failure. The scheduler now throttles one destination, and
      allows deliveries to other destinations to keep making
      progress. Files: *qmgr/qmgr_deliver.c.
    - Safety: drop and log over-size DNS responses resulting in
      more than 100 records. This 20x larger than the number of
      server addresses that the Postfix SMTP client is willing
      to consider when delivering mail, and is well below the
      number of records that could cause a tail recursion crash
      in dns_rr_append() as reported by Toshifumi Sakaguchi. This
      also limits the number of DNS requests from check_*_*_access
      restrictions. Files: dns/dns.h, dns/dns_lookup.c, dns/dns_rr.c,
      dns/test_dns_lookup.c, posttls-finger/posttls-finger.c,
      smtp/smtp_addr.c, smtpd/smtpd_check.c.

[ Other info ]
N/A

Scott K
diff -Nru postfix-3.7.10/debian/changelog postfix-3.7.11/debian/changelog
--- postfix-3.7.10/debian/changelog	2024-01-26 18:44:58.000000000 -0500
+++ postfix-3.7.11/debian/changelog	2024-03-06 10:10:14.000000000 -0500
@@ -1,3 +1,66 @@
+postfix (3.7.11-0+deb12u1) bookworm; urgency=medium
+
+  [Wietse Venema]
+
+  * 3.7.11
+    - Bugfix (defect introduced: Postfix 2.3, date 20051222): the
+      Dovecot auth client did not reset the 'reason' from  a
+      previous Dovecot auth service response, before parsing the
+      next Dovecot auth server response in the same SMTP session.
+      Reported by Stephan Bosch, File: xsasl/xsasl_dovecot_server.c.
+    - Cleanup: Postfix SMTP server response with an empty
+      authentication failure reason. File: smtpd/smtpd_sasl_glue.c.
+    - Bugfix (defect introduced: Postfix 3.1, date: 20151128):
+      "postqueue -j" produced broken JSON when escaping a control
+      character as \uXXXX. Found during code maintenance. File:
+      postqueue/showq_json.c.
+    - Cleanup: posttls-finger certificate match expectations for
+      all TLS security levels, including warnings for levels that
+      don't implement certificate matching. Viktor Dukhovni.
+      File: posttls-finger.c.
+    - Bugfix (defect introduced: Postfix 2.3): after prepending
+      a message header with a Postfix access table PREPEND action,
+      a Milter request to delete or update an existing header
+      could have no effect, or it could target the wrong instance
+      of an existing header. Root cause: the fix dated 20141018
+      for the Postfix Milter client was incomplete. The client
+      did correctly hide the first, Postfix-generated, Received:
+      header when sending message header information to a Milter
+      with the smfi_header() application callback function, but
+      it was still hiding the first header (instead of the first
+      Received: header) when handling requests from a Milter to
+      delete or update an existing header. Problem report by
+      Carlos Velasco. This change was verified to have no effect
+      on requests from a Milter to add or insert a header. File:
+      cleanup/cleanup_milter.c.
+    - Workaround: tlsmgr logfile spam. Some OS lies under load:
+      it says that a socket is readable, then it says that the
+      socket has unread data, and then it says that read returns
+      EOF, causing Postfix to spam the log with a warning message.
+      File: tlsmgr/tlsmgr.c.
+    - Bugfix (defect introduced: Postfix 3.4): the SMTP server's
+      BDAT command handler could be tricked to read $message_size_limit
+      bytes into memory. Found during code maintenance. File:
+      smtpd/smtpd.c.
+    - Performance: eliminate worst-case behavior where the queue
+      manager defers delivery to all destinations over a specific
+      delivery transport, after only a single delivery agent
+      failure. The scheduler now throttles one destination, and
+      allows deliveries to other destinations to keep making
+      progress. Files: *qmgr/qmgr_deliver.c.
+    - Safety: drop and log over-size DNS responses resulting in
+      more than 100 records. This 20x larger than the number of
+      server addresses that the Postfix SMTP client is willing
+      to consider when delivering mail, and is well below the
+      number of records that could cause a tail recursion crash
+      in dns_rr_append() as reported by Toshifumi Sakaguchi. This
+      also limits the number of DNS requests from check_*_*_access
+      restrictions. Files: dns/dns.h, dns/dns_lookup.c, dns/dns_rr.c,
+      dns/test_dns_lookup.c, posttls-finger/posttls-finger.c,
+      smtp/smtp_addr.c, smtpd/smtpd_check.c. 
+
+ -- Scott Kitterman <scott@kitterman.com>  Wed, 06 Mar 2024 10:10:14 -0500
+
 postfix (3.7.10-0+deb12u1) bookworm; urgency=medium
 
   [Wietse Venema]
diff -Nru postfix-3.7.10/HISTORY postfix-3.7.11/HISTORY
--- postfix-3.7.10/HISTORY	2024-01-19 11:52:30.000000000 -0500
+++ postfix-3.7.11/HISTORY	2024-02-27 15:58:54.000000000 -0500
@@ -26681,3 +26681,83 @@
 	Files: mantools/postlink, proto/postconf.proto,
 	global/mail_params.h, global/smtp_stream.c, global/smtp_stream.h,
 	smtpd/smtpd.c, smtpd/smtpd_check.[hc].
+
+20231102
+
+	Bugfix (defect introduced: Postfix 2.3, date 20051222): the
+	Dovecot auth client did not reset the 'reason' from  a
+	previous Dovecot auth service response, before parsing the
+	next Dovecot auth server response in the same SMTP session.
+	Reported by Stephan Bosch, File: xsasl/xsasl_dovecot_server.c.
+
+20231105
+
+	Cleanup: Postfix SMTP server response with an empty
+	authentication failure reason. File: smtpd/smtpd_sasl_glue.c.
+
+20231208
+
+	Bugfix (defect introduced: Postfix 3.1, date: 20151128):
+	"postqueue -j" produced broken JSON when escaping a control
+	character as \uXXXX. Found during code maintenance. File:
+	postqueue/showq_json.c.
+
+20231211
+
+	Cleanup: posttls-finger certificate match expectations for
+	all TLS security levels, including warnings for levels that
+	don't implement certificate matching. Viktor Dukhovni.
+	File: posttls-finger.c.
+
+20231213
+
+	Bugfix (defect introduced: Postfix 2.3): after prepending
+	a message header with a Postfix access table PREPEND action,
+	a Milter request to delete or update an existing header
+	could have no effect, or it could target the wrong instance
+	of an existing header. Root cause: the fix dated 20141018
+	for the Postfix Milter client was incomplete. The client
+	did correctly hide the first, Postfix-generated, Received:
+	header when sending message header information to a Milter
+	with the smfi_header() application callback function, but
+	it was still hiding the first header (instead of the first
+	Received: header) when handling requests from a Milter to
+	delete or update an existing header. Problem report by
+	Carlos Velasco. This change was verified to have no effect
+	on requests from a Milter to add or insert a header. File:
+	cleanup/cleanup_milter.c.
+
+20240124
+
+	Workaround: tlsmgr logfile spam. Some OS lies under load:
+	it says that a socket is readable, then it says that the
+	socket has unread data, and then it says that read returns
+	EOF, causing Postfix to spam the log with a warning message.
+	File: tlsmgr/tlsmgr.c.
+
+	Bugfix (defect introduced: Postfix 3.4): the SMTP server's
+	BDAT command handler could be tricked to read $message_size_limit
+	bytes into memory. Found during code maintenance. File:
+	smtpd/smtpd.c.
+
+20240209
+
+	Performance: eliminate worst-case behavior where the queue
+	manager defers delivery to all destinations over a specific
+	delivery transport, after only a single delivery agent
+	failure. The scheduler now throttles one destination, and
+	allows deliveries to other destinations to keep making
+	progress. Files: *qmgr/qmgr_deliver.c.
+
+20240226
+
+	Safety: drop and log over-size DNS responses resulting in
+	more than 100 records. This 20x larger than the number of
+	server addresses that the Postfix SMTP client is willing
+	to consider when delivering mail, and is well below the
+	number of records that could cause a tail recursion crash
+	in dns_rr_append() as reported by Toshifumi Sakaguchi. This
+	also limits the number of DNS requests from check_*_*_access
+	restrictions. Files: dns/dns.h, dns/dns_lookup.c, dns/dns_rr.c,
+	dns/test_dns_lookup.c, posttls-finger/posttls-finger.c,
+	smtp/smtp_addr.c, smtpd/smtpd_check.c.
diff -Nru postfix-3.7.10/src/cleanup/cleanup_milter.c postfix-3.7.11/src/cleanup/cleanup_milter.c
--- postfix-3.7.10/src/cleanup/cleanup_milter.c	2022-09-06 15:42:02.000000000 -0400
+++ postfix-3.7.11/src/cleanup/cleanup_milter.c	2024-02-27 12:17:44.000000000 -0500
@@ -119,6 +119,7 @@
 #include <dsn_util.h>
 #include <xtext.h>
 #include <info_log_addr_form.h>
+#include <header_opts.h>
 
 /* Application-specific. */
 
@@ -754,14 +755,26 @@
      */
 }
 
+/* hidden_header - respect milter header hiding protocol */
+
+static int hidden_header(VSTRING *buf, ARGV *auto_hdrs, int *hide_done)
+{
+    char  **cpp;
+    int     mask;
+
+    for (cpp = auto_hdrs->argv, mask = 1; *cpp; cpp++, mask <<= 1)
+	if ((*hide_done & mask) == 0 && strncmp(*cpp, STR(buf), LEN(buf)) == 0)
+	    return (*hide_done |= mask);
+    return (0);
+}
+
 /* cleanup_find_header_start - find specific header instance */
 
 static off_t cleanup_find_header_start(CLEANUP_STATE *state, ssize_t index,
 				               const char *header_label,
 				               VSTRING *buf,
 				               int *prec_type,
-				               int allow_ptr_backup,
-				               int skip_headers)
+				               int allow_ptr_backup)
 {
     const char *myname = "cleanup_find_header_start";
     off_t   curr_offset;		/* offset after found record */
@@ -770,7 +783,7 @@
     int     rec_type = REC_TYPE_ERROR;
     int     last_type;
     ssize_t len;
-    int     hdr_count = 0;
+    int     hide_done = 0;
 
     if (msg_verbose)
 	msg_info("%s: index %ld name \"%s\"",
@@ -912,11 +925,10 @@
 	    break;
 	}
 	/* This the start of a message header. */
-	else if (hdr_count++ < skip_headers)
-	     /* Reset the saved PTR record and update last_type. */ ;
 	else if ((header_label == 0
 		  || (strncasecmp(header_label, STR(buf), len) == 0
-		      && (strlen(header_label) == len)))
+		      && strlen(header_label) == len
+		      && !hidden_header(buf, state->auto_hdrs, &hide_done)))
 		 && --index == 0) {
 	    /* If we have a saved PTR record, it points to start of header. */
 	    break;
@@ -1182,15 +1194,12 @@
      */
 #define NO_HEADER_NAME	((char *) 0)
 #define ALLOW_PTR_BACKUP	1
-#define SKIP_ONE_HEADER		1
-#define DONT_SKIP_HEADERS	0
 
     if (index < 1)
 	index = 1;
     old_rec_offset = cleanup_find_header_start(state, index, NO_HEADER_NAME,
 					       old_rec_buf, &old_rec_type,
-					       ALLOW_PTR_BACKUP,
-					       DONT_SKIP_HEADERS);
+					       ALLOW_PTR_BACKUP);
     if (old_rec_offset == CLEANUP_FIND_HEADER_IOERROR)
 	/* Warning and errno->error mapping are done elsewhere. */
 	CLEANUP_INS_HEADER_RETURN(cleanup_milter_error(state, 0));
@@ -1270,8 +1279,7 @@
     rec_buf = vstring_alloc(100);
     old_rec_offset = cleanup_find_header_start(state, index, new_hdr_name,
 					       rec_buf, &last_type,
-					       NO_PTR_BACKUP,
-					       SKIP_ONE_HEADER);
+					       NO_PTR_BACKUP);
     if (old_rec_offset == CLEANUP_FIND_HEADER_IOERROR)
 	/* Warning and errno->error mapping are done elsewhere. */
 	CLEANUP_UPD_HEADER_RETURN(cleanup_milter_error(state, 0));
@@ -1333,8 +1341,7 @@
 
     rec_buf = vstring_alloc(100);
     header_offset = cleanup_find_header_start(state, index, hdr_name, rec_buf,
-					      &last_type, NO_PTR_BACKUP,
-					      SKIP_ONE_HEADER);
+					      &last_type, NO_PTR_BACKUP);
     if (header_offset == CLEANUP_FIND_HEADER_IOERROR)
 	/* Warning and errno->error mapping are done elsewhere. */
 	CLEANUP_DEL_HEADER_RETURN(cleanup_milter_error(state, 0));
diff -Nru postfix-3.7.10/src/dns/dns.h postfix-3.7.11/src/dns/dns.h
--- postfix-3.7.10/src/dns/dns.h	2021-01-16 17:37:07.000000000 -0500
+++ postfix-3.7.11/src/dns/dns.h	2024-02-28 13:33:25.000000000 -0500
@@ -159,11 +159,17 @@
     unsigned int ttl;			/* always */
     unsigned int dnssec_valid;		/* DNSSEC validated */
     unsigned short pref;		/* T_MX only */
+    /* Assume that flags lives in what was previously padding */
+    unsigned short flags;		/* DNS_RR_FLAG_XX, see below */
     struct DNS_RR *next;		/* linkage */
     size_t  data_len;			/* actual data size */
     char    data[1];			/* actually a bunch of data */
 } DNS_RR;
 
+#define DNS_RR_FLAG_TRUNCATED	(1<<0)
+
+#define DNS_RR_IS_TRUNCATED(rr)	((rr)->flags & DNS_RR_FLAG_TRUNCATED)
+
  /*
   * dns_strerror.c
   */
@@ -197,6 +203,7 @@
 extern int dns_rr_compare_pref(DNS_RR *, DNS_RR *);
 extern DNS_RR *dns_rr_shuffle(DNS_RR *);
 extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *);
+extern int var_dns_rr_list_limit;
 
  /*
   * dns_rr_to_pa.c
diff -Nru postfix-3.7.10/src/dns/dns_lookup.c postfix-3.7.11/src/dns/dns_lookup.c
--- postfix-3.7.10/src/dns/dns_lookup.c	2023-09-01 09:01:13.000000000 -0400
+++ postfix-3.7.11/src/dns/dns_lookup.c	2024-02-27 12:53:36.000000000 -0500
@@ -960,6 +960,8 @@
 		    resource_found++;
 		    rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0;
 		    *rrlist = dns_rr_append(*rrlist, rr);
+		    if (DNS_RR_IS_TRUNCATED(*rrlist))
+			break;
 		} else if (status == DNS_NULLMX) {
 		    CORRUPT(status);		/* TODO: use better name */
 		} else if (not_found_status != DNS_RETRY)
@@ -1184,8 +1186,11 @@
 		     name, dns_strtype(type), dns_str_resflags(flags));
 	status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
 			      fqdn, why, rcode, lflags);
-	if (rrlist && rr)
+	if (rrlist && rr) {
 	    *rrlist = dns_rr_append(*rrlist, rr);
+	    if (DNS_RR_IS_TRUNCATED(*rrlist))
+		break;
+	}
 	if (status == DNS_OK) {
 	    if (lflags & DNS_REQ_FLAG_STOP_OK)
 		break;
@@ -1236,8 +1241,11 @@
 		     name, dns_strtype(type), dns_str_resflags(flags));
 	status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
 			      fqdn, why, rcode, lflags);
-	if (rrlist && rr)
+	if (rrlist && rr) {
 	    *rrlist = dns_rr_append(*rrlist, rr);
+	    if (DNS_RR_IS_TRUNCATED(*rrlist))
+		break;
+	}
 	if (status == DNS_OK) {
 	    if (lflags & DNS_REQ_FLAG_STOP_OK)
 		break;
diff -Nru postfix-3.7.10/src/dns/dns_rr.c postfix-3.7.11/src/dns/dns_rr.c
--- postfix-3.7.10/src/dns/dns_rr.c	2014-12-06 20:35:32.000000000 -0500
+++ postfix-3.7.11/src/dns/dns_rr.c	2024-02-27 12:48:07.000000000 -0500
@@ -49,6 +49,8 @@
 /*	DNS_RR	*dns_rr_remove(list, record)
 /*	DNS_RR	*list;
 /*	DNS_RR	*record;
+/*
+/*	int	var_dns_rr_list_limit;
 /* DESCRIPTION
 /*	The routines in this module maintain memory for DNS resource record
 /*	information, and maintain lists of DNS resource records.
@@ -65,9 +67,17 @@
 /*
 /*	dns_rr_copy() makes a copy of a resource record.
 /*
-/*	dns_rr_append() appends a resource record to a (list of) resource
-/*	record(s).
-/*	A null input list is explicitly allowed.
+/*	dns_rr_append() appends an input resource record list to
+/*	an output list. Null arguments are explicitly allowed.
+/*	When the result would be longer than var_dns_rr_list_limit
+/*	(default: 100), dns_rr_append() logs a warning, flags the
+/*	output list as truncated, and discards the excess elements.
+/*	Once an output list is flagged as truncated (test with
+/*	DNS_RR_IS_TRUNCATED()), the caller is expected to stop
+/*	trying to append records to that list. Note: the 'truncated'
+/*	flag is transitive, i.e. when appending a input list that
+/*	was flagged as truncated to an output list, the output list
+/*	will also be flagged as truncated.
 /*
 /*	dns_rr_sort() sorts a list of resource records into ascending
 /*	order according to a user-specified criterion. The result is the
@@ -108,6 +118,16 @@
 
 #include "dns.h"
 
+ /*
+  * A generous safety limit for the number of DNS resource records that the
+  * Postfix DNS client library will admit into a list. The default value 100
+  * is 20x the default limit on the number address records that the Postfix
+  * SMTP client is willing to consider.
+  * 
+  * Mutable, to make code testable.
+  */
+int     var_dns_rr_list_limit = 100;
+
 /* dns_rr_create - fill in resource record structure */
 
 DNS_RR *dns_rr_create(const char *qname, const char *rname,
@@ -129,6 +149,7 @@
 	memcpy(rr->data, data, data_len);
     rr->data_len = data_len;
     rr->next = 0;
+    rr->flags = 0;
     return (rr);
 }
 
@@ -163,14 +184,58 @@
     return (dst);
 }
 
-/* dns_rr_append - append resource record to list */
+/* dns_rr_append_with_limit - append resource record to limited list */
+
+static void dns_rr_append_with_limit(DNS_RR *list, DNS_RR *rr, int limit)
+{
+
+    /*
+     * Pre: list != 0, all lists are concatenated with dns_rr_append().
+     * 
+     * Post: all elements have the DNS_RR_FLAG_TRUNCATED flag value set, or all
+     * elements have it cleared, so that there is no need to update code in
+     * legacy stable releases that deletes or reorders elements.
+     */
+    if (limit <= 1) {
+	if (list->next || rr) {
+	    msg_warn("DNS record count limit (%d) exceeded -- dropping"
+		     " excess record(s) after qname=%s qtype=%s",
+		     var_dns_rr_list_limit, list->qname,
+		     dns_strtype(list->type));
+	    list->flags |= DNS_RR_FLAG_TRUNCATED;
+	    dns_rr_free(list->next);
+	    dns_rr_free(rr);
+	    list->next = 0;
+	}
+    } else {
+	if (list->next == 0 && rr) {
+	    list->next = rr;
+	    rr = 0;
+	}
+	if (list->next) {
+	    dns_rr_append_with_limit(list->next, rr, limit - 1);
+	    list->flags |= list->next->flags;
+	}
+    }
+}
+
+/* dns_rr_append - append resource record(s) to list, or discard */
 
 DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr)
 {
-    if (list == 0) {
-	list = rr;
+
+    /*
+     * Note: rr is not length checked; when multiple lists are concatenated,
+     * the output length may be a small multiple of var_dns_rr_list_limit.
+     */
+    if (rr == 0)
+	return (list);
+    if (list == 0)
+	return (rr);
+    if (!DNS_RR_IS_TRUNCATED(list)) {
+	dns_rr_append_with_limit(list, rr, var_dns_rr_list_limit);
     } else {
-	list->next = dns_rr_append(list->next, rr);
+	dns_rr_free(rr);
     }
     return (list);
 }
diff -Nru postfix-3.7.10/src/dns/test_dns_lookup.c postfix-3.7.11/src/dns/test_dns_lookup.c
--- postfix-3.7.10/src/dns/test_dns_lookup.c	2021-04-04 11:40:41.000000000 -0400
+++ postfix-3.7.11/src/dns/test_dns_lookup.c	2024-02-27 12:25:43.000000000 -0500
@@ -121,9 +121,11 @@
 	    vstream_printf("%s: fqdn: %s\n", name, vstring_str(fqdn));
 	    buf = vstring_alloc(100);
 	    print_rr(buf, rr);
+	    vstream_fflush(VSTREAM_OUT);
+	    if (DNS_RR_IS_TRUNCATED(rr))
+		msg_warn("one or more excess DNS_RR records were dropped");
 	    dns_rr_free(rr);
 	    vstring_free(buf);
-	    vstream_fflush(VSTREAM_OUT);
 	}
     }
     myfree((void *) types);
diff -Nru postfix-3.7.10/src/global/mail_version.h postfix-3.7.11/src/global/mail_version.h
--- postfix-3.7.10/src/global/mail_version.h	2024-01-19 11:55:40.000000000 -0500
+++ postfix-3.7.11/src/global/mail_version.h	2024-03-04 11:50:50.000000000 -0500
@@ -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	"20240121"
-#define MAIL_VERSION_NUMBER	"3.7.10"
+#define MAIL_RELEASE_DATE	"20240304"
+#define MAIL_VERSION_NUMBER	"3.7.11"
 
 #ifdef SNAPSHOT
 #define MAIL_VERSION_DATE	"-" MAIL_RELEASE_DATE
diff -Nru postfix-3.7.10/src/oqmgr/qmgr_deliver.c postfix-3.7.11/src/oqmgr/qmgr_deliver.c
--- postfix-3.7.10/src/oqmgr/qmgr_deliver.c	2021-08-06 20:04:05.000000000 -0400
+++ postfix-3.7.11/src/oqmgr/qmgr_deliver.c	2024-02-27 12:24:33.000000000 -0500
@@ -283,6 +283,7 @@
      * The queue itself won't go away before we dispose of the current queue
      * entry.
      */
+#if 0
     if (status == DELIVER_STAT_CRASH) {
 	message->flags |= DELIVER_STAT_DEFER;
 #if 0
@@ -317,6 +318,7 @@
 	qmgr_defer_transport(transport, &dsb->dsn);
 	return;
     }
+#endif
 
     /*
      * This message must be tried again.
@@ -331,7 +333,9 @@
      */
 #define SUSPENDED	"delivery temporarily suspended: "
 
-    if (status == DELIVER_STAT_DEFER) {
+    if (status == DELIVER_STAT_CRASH)
+	DSN_SIMPLE(&dsb->dsn, "4.3.0", "unknown mail transport error");
+    if (status == DELIVER_STAT_CRASH || status == DELIVER_STAT_DEFER) {
 	message->flags |= DELIVER_STAT_DEFER;
 	if (VSTRING_LEN(dsb->status)) {
 	    /* Sanitize the DSN status/reason from the delivery agent. */
diff -Nru postfix-3.7.10/src/postqueue/showq_json.c postfix-3.7.11/src/postqueue/showq_json.c
--- postfix-3.7.10/src/postqueue/showq_json.c	2021-10-27 19:33:07.000000000 -0400
+++ postfix-3.7.11/src/postqueue/showq_json.c	2024-02-27 12:17:44.000000000 -0500
@@ -96,7 +96,7 @@
 		VSTRING_ADDCH(result, 't');
 		break;
 	    default:
-		vstring_sprintf(result, "\\u%04X", ch);
+		vstring_sprintf_append(result, "\\u%04X", ch);
 		break;
 	    }
 	} else {
diff -Nru postfix-3.7.10/src/posttls-finger/posttls-finger.c postfix-3.7.11/src/posttls-finger/posttls-finger.c
--- postfix-3.7.10/src/posttls-finger/posttls-finger.c	2023-01-27 15:55:23.000000000 -0500
+++ postfix-3.7.11/src/posttls-finger/posttls-finger.c	2024-02-27 12:28:33.000000000 -0500
@@ -1252,6 +1252,8 @@
 		    msg_fatal("host %s: conversion error for address family %d: %m",
 		    host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
 		addr_list = dns_rr_append(addr_list, addr);
+		if (DNS_RR_IS_TRUNCATED(addr_list))
+		    break;
 	    }
 	    freeaddrinfo(res0);
 	    if (found == 0) {
@@ -1289,6 +1291,8 @@
 	    msg_panic("%s: bad resource type: %d", myname, rr->type);
 	addr_list = addr_one(state, addr_list, (char *) rr->data, res_opt,
 			     rr->pref);
+	if (addr_list && DNS_RR_IS_TRUNCATED(addr_list))
+	    break;
     }
     return (addr_list);
 }
@@ -2024,7 +2028,19 @@
 #ifdef USE_TLS
     int     smtp_mode = 1;
 
+    /*
+     * DANE match names are configured late, once the TLSA records are in
+     * hand. For now, prepare to fall back to "secure".
+     */
     switch (state->level) {
+    default:
+	state->match = 0;
+	if (*argv)
+	    msg_warn("TLS level '%s' does not implement certificate matching",
+		     str_tls_level(state->level));
+	break;
+    case TLS_LEV_DANE:
+    case TLS_LEV_DANE_ONLY:
     case TLS_LEV_SECURE:
 	state->match = argv_alloc(2);
 	while (*argv)
@@ -2045,11 +2061,6 @@
 	    tls_dane_add_fpt_digests((TLS_DANE *) state->dane, *argv++, "",
 				     smtp_mode);
 	break;
-    case TLS_LEV_DANE:
-    case TLS_LEV_DANE_ONLY:
-	state->match = argv_alloc(2);
-	argv_add(state->match, "nexthop", "hostname", ARGV_END);
-	break;
     }
 #endif
 }
diff -Nru postfix-3.7.10/src/qmgr/qmgr_deliver.c postfix-3.7.11/src/qmgr/qmgr_deliver.c
--- postfix-3.7.10/src/qmgr/qmgr_deliver.c	2021-08-06 20:04:05.000000000 -0400
+++ postfix-3.7.11/src/qmgr/qmgr_deliver.c	2024-02-27 12:24:33.000000000 -0500
@@ -288,6 +288,7 @@
      * The queue itself won't go away before we dispose of the current queue
      * entry.
      */
+#if 0
     if (status == DELIVER_STAT_CRASH) {
 	message->flags |= DELIVER_STAT_DEFER;
 #if 0
@@ -322,6 +323,7 @@
 	qmgr_defer_transport(transport, &dsb->dsn);
 	return;
     }
+#endif
 
     /*
      * This message must be tried again.
@@ -336,7 +338,9 @@
      */
 #define SUSPENDED	"delivery temporarily suspended: "
 
-    if (status == DELIVER_STAT_DEFER) {
+    if (status == DELIVER_STAT_CRASH)
+	DSN_SIMPLE(&dsb->dsn, "4.3.0", "unknown mail transport error");
+    if (status == DELIVER_STAT_CRASH || status == DELIVER_STAT_DEFER) {
 	message->flags |= DELIVER_STAT_DEFER;
 	if (VSTRING_LEN(dsb->status)) {
 	    /* Sanitize the DSN status/reason from the delivery agent. */
diff -Nru postfix-3.7.10/src/smtp/smtp_addr.c postfix-3.7.11/src/smtp/smtp_addr.c
--- postfix-3.7.10/src/smtp/smtp_addr.c	2020-07-27 09:34:25.000000000 -0400
+++ postfix-3.7.11/src/smtp/smtp_addr.c	2024-02-28 14:41:28.000000000 -0500
@@ -154,7 +154,7 @@
 		msg_fatal("host %s: conversion error for address family "
 			  "%d: %m", host, res0->ai_addr->sa_family);
 	    addr_list = dns_rr_append(addr_list, addr);
-	    if (msg_verbose)
+	    if (msg_verbose && !DNS_RR_IS_TRUNCATED(addr_list))
 		msg_info("%s: using numerical host %s", myname, host);
 	    freeaddrinfo(res0);
 	    return (addr_list);
@@ -232,6 +232,8 @@
 		    msg_fatal("host %s: conversion error for address family "
 			      "%d: %m", host, res0->ai_addr->sa_family);
 		addr_list = dns_rr_append(addr_list, addr);
+		if (DNS_RR_IS_TRUNCATED(addr_list))
+		    break;
 		if (msg_verbose) {
 		    MAI_HOSTADDR_STR hostaddr_str;
 
@@ -297,6 +299,8 @@
 	    msg_panic("smtp_addr_list: bad resource type: %d", rr->type);
 	addr_list = smtp_addr_one(addr_list, (char *) rr->data, res_opt,
 				  rr->pref, why);
+	if (addr_list && DNS_RR_IS_TRUNCATED(addr_list))
+	    break;
     }
     return (addr_list);
 }
@@ -391,6 +395,13 @@
      */
 
     /*
+     * Ensure that dns_rr_append() won't interfere with the protocol
+     * balancing goals.
+     */
+    if (addr_limit > var_dns_rr_list_limit)
+	addr_limit = var_dns_rr_list_limit;
+
+    /*
      * Count the number of IPv6 and IPv4 addresses.
      */
     for (v4_count = v6_count = 0, rr = addr_list; rr != 0; rr = rr->next) {
diff -Nru postfix-3.7.10/src/smtpd/smtpd.c postfix-3.7.11/src/smtpd/smtpd.c
--- postfix-3.7.10/src/smtpd/smtpd.c	2024-01-19 12:15:47.000000000 -0500
+++ postfix-3.7.11/src/smtpd/smtpd.c	2024-02-27 12:22:29.000000000 -0500
@@ -4114,14 +4114,31 @@
 	/*
 	 * Read lines from the fragment. The last line may continue in the
 	 * next fragment, or in the next chunk.
+	 * 
+	 * If smtp_get_noexcept() stopped after var_line_limit bytes and did not
+	 * emit a queue file record, then that means smtp_get_noexcept()
+	 * stopped after CR and hit EOF as it tried to find out if the next
+	 * byte is LF. In that case, read the first byte from the next
+	 * fragment or chunk, and if that first byte is LF, then
+	 * smtp_get_noexcept() strips off the trailing CRLF and returns '\n'
+	 * as it always does after reading a complete line.
 	 */
 	do {
+	    int     can_read = var_line_limit - LEN(state->bdat_get_buffer);
+
 	    if (smtp_get_noexcept(state->bdat_get_buffer,
 				  state->bdat_get_stream,
-				  var_line_limit,
+				  can_read > 0 ? can_read : 1,	/* Peek one */
 				  SMTP_GET_FLAG_APPEND) == '\n') {
 		/* Stopped at end-of-line. */
 		curr_rec_type = REC_TYPE_NORM;
+	    } else if (LEN(state->bdat_get_buffer) > var_line_limit) {
+		/* Undo peeking, and output the buffer as REC_TYPE_CONT. */
+		vstream_ungetc(state->bdat_get_stream,
+			       vstring_end(state->bdat_get_buffer)[-1]);
+		vstring_truncate(state->bdat_get_buffer,
+				 LEN(state->bdat_get_buffer) - 1);
+		curr_rec_type = REC_TYPE_CONT;
 	    } else if (!vstream_feof(state->bdat_get_stream)) {
 		/* Stopped at var_line_limit. */
 		curr_rec_type = REC_TYPE_CONT;
diff -Nru postfix-3.7.10/src/smtpd/smtpd_check.c postfix-3.7.11/src/smtpd/smtpd_check.c
--- postfix-3.7.10/src/smtpd/smtpd_check.c	2024-01-19 11:52:30.000000000 -0500
+++ postfix-3.7.11/src/smtpd/smtpd_check.c	2024-02-27 12:25:43.000000000 -0500
@@ -2993,6 +2993,7 @@
     struct addrinfo *res;
     int     status;
     const INET_PROTO_INFO *proto_info;
+    int     server_addr_count = 0;
 
     /*
      * Sanity check.
@@ -3144,6 +3145,15 @@
 	    msg_info("%s: %s host address check: %s",
 		     myname, dns_strtype(type), (char *) server->data);
 	for (res = res0; res != 0; res = res->ai_next) {
+	    server_addr_count += 1;
+	    if (server_addr_count > var_dns_rr_list_limit) {
+		msg_warn("%s: %s server address count limit (%d) exceeded"
+			 " for %s %s -- ignoring the remainder", myname,
+			 dns_strtype(type), var_dns_rr_list_limit,
+			 reply_class, reply_name);
+		freeaddrinfo(res0);
+		CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
+	    }
 	    if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
 		if (msg_verbose)
 		    msg_info("skipping address family %d for host %s",
diff -Nru postfix-3.7.10/src/smtpd/smtpd_sasl_glue.c postfix-3.7.11/src/smtpd/smtpd_sasl_glue.c
--- postfix-3.7.10/src/smtpd/smtpd_sasl_glue.c	2023-10-30 19:18:24.000000000 -0400
+++ postfix-3.7.11/src/smtpd/smtpd_sasl_glue.c	2024-02-27 12:17:44.000000000 -0500
@@ -340,18 +340,20 @@
 	}
     }
     if (status != XSASL_AUTH_DONE) {
+	const char *reason = (*STR(state->sasl_reply) ? STR(state->sasl_reply) :
+			      "(reason unavailable)");
+
 	sasl_username = xsasl_server_get_username(state->sasl_server);
 	msg_warn("%s: SASL %.100s authentication failed: %s, sasl_username=%.100s",
-		 state->namaddr, sasl_method, *STR(state->sasl_reply) ?
-		 STR(state->sasl_reply) : "(reason unavailable)",
+		 state->namaddr, sasl_method, reason,
 		 sasl_username ? sasl_username : "(unavailable)");
 	/* RFC 4954 Section 6. */
 	if (status == XSASL_AUTH_TEMP)
 	    smtpd_chat_reply(state, "454 4.7.0 Temporary authentication failure: %s",
-			     STR(state->sasl_reply));
+			     reason);
 	else
 	    smtpd_chat_reply(state, "535 5.7.8 Error: authentication failed: %s",
-			     STR(state->sasl_reply));
+			     reason);
 	return (-1);
     }
     /* RFC 4954 Section 6. */
diff -Nru postfix-3.7.10/src/tlsmgr/tlsmgr.c postfix-3.7.11/src/tlsmgr/tlsmgr.c
--- postfix-3.7.10/src/tlsmgr/tlsmgr.c	2021-12-19 17:04:54.000000000 -0500
+++ postfix-3.7.11/src/tlsmgr/tlsmgr.c	2024-02-27 12:19:24.000000000 -0500
@@ -819,6 +819,23 @@
     }
 
     /*
+     * Workaround: some OS lies under load. It tells the Postfix event
+     * handler that a server socket is readable, then it tells peekfd() that
+     * the socket has unread data, and then it tells vstring_get_null() that
+     * there is none, causing Postfix to spam the log with warning messages.
+     * Close the stream to stop such nonsense; the client can reconnect if it
+     * still wants to talk to us.
+     * 
+     * XXX Why is this problem not reported for the other five
+     * multi_server-based Postfix services?
+     */
+    else if (vstream_ferror(client_stream) || vstream_feof(client_stream)) {
+	multi_server_disconnect(client_stream);
+	return;
+	/* Note: client_stream is now a dangling pointer. */
+    }
+
+    /*
      * Protocol error.
      */
     else {
diff -Nru postfix-3.7.10/src/xsasl/xsasl_dovecot_server.c postfix-3.7.11/src/xsasl/xsasl_dovecot_server.c
--- postfix-3.7.10/src/xsasl/xsasl_dovecot_server.c	2022-01-02 18:25:27.000000000 -0500
+++ postfix-3.7.11/src/xsasl/xsasl_dovecot_server.c	2024-02-27 12:17:44.000000000 -0500
@@ -543,6 +543,8 @@
 	myfree(server->username);
 	server->username = 0;
     }
+    VSTRING_RESET(reply);
+    VSTRING_TERMINATE(reply);
 
     /*
      * Note: TAB is part of the Dovecot protocol and must not appear in

Reply to: