From: Wietse Z Venema Date: Mon, 6 Jul 2026 05:00:00 +0000 (-0500) Subject: postfix-3.12-20260709 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=58ac228ae3aa466eaba256d2ac2ad71aefd96434;p=thirdparty%2Fpostfix.git postfix-3.12-20260709 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index fc597d994..c22b0b2f7 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -31599,6 +31599,60 @@ Apologies for any names omitted. yet reused. Reported by Qualys, assisted by Claude Mythos Preview. File: postdrop.c. +20260708 + + Bug (defect introduced: Postfix 3.0, date: 20141117): don't + free() text before logging a fatal error message. Reported + by Qualys, assisted by Claude Mythos Preview. File: + postqueue/postqueue.c. + + Code hygiene: swap the 'offset' and 'whence' arguments in + vstream_fseek() calls. Reported by Qualys, assisted by + Claude Mythos Preview. Files: postmap.c, postalias.c. + + Bug (defect introduced: before Postfix alpha, date: 19971029): + don't allow type-0 records. Reported by Qualys, assisted + by Claude Mythos Preview. File: pickup.c. + + Code hygiene: don't allow type-0 records. File: postdrop.c. + + Bug (defect introduced: Postfix 2.3, date: 20050323): the + SMTP client enhanced status code parser could process stale + data. Reported by Qualys, assisted by Claude Mythos Preview. + File: smtp_chat.c. + +20260709 + + Future proofing in smtpd_xforward_init(). Suggested by + Qualys, assisted by Claude Mythos Preview. File: smtpd_xforward.c. + + Bug (defect introduced: Postfix 3.6, date: 20200710): memory + leak in tls_dane_add_fpt_digests(), triggered by local + configuration error. Reported by Qualys, assisted by Claude + Mythos Preview. File: tls_dane.c. + + Bug (defect introduced: before Postfix alpha, date: 19970323): + the strerror() emulation function used the wrong indexing + variable. This function is used on systems from the previous + century. Reported by Qualys, assisted by Claude Mythos + Preview. File: sys_compat.c. + + Bug (defect introduced: before Postfix alpha, date: 19970411): + the unused vstring_import() function did not respect a + VSTRING invariant. Reported by Qualys, assisted by Claude + Mythos Preview. File: vstring.c. + + Latent bug (defect introduced: Postfix 3.6, date: 20200710): in + tls_scache_decode(), enforce a minimum length invariant by + disallowing ':' in hex-encoded TLS session cache entries. + Reported by Qualys, assisted by Claude Mythos Preview. File: + tls_scache.c. + + Latent bug (defect introduced: Postfix 3.11, date: 20260219): + The DICT_FLAG_SURROGATE flag was mis-implemented. This flag + was used in test code. Reported by Qualys, assisted by + Claude Mythos Preview. Files: dict.h, dict.c. + TODO Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc. diff --git a/postfix/src/pickup/pickup.c b/postfix/src/pickup/pickup.c index 390329d1e..fa08ad038 100644 --- a/postfix/src/pickup/pickup.c +++ b/postfix/src/pickup/pickup.c @@ -247,7 +247,8 @@ static int copy_segment(VSTREAM *qfile, VSTREAM *cleanup, PICKUP_INFO *info, * We must allow PTR records here because of "postsuper -r". */ for (;;) { - if ((type = rec_get(qfile, buf, var_line_limit)) < 0 + /* 202606 Qualys+Mythos: don't allow type-0 records. */ + if ((type = rec_get(qfile, buf, var_line_limit)) <= 0 || strchr(expected, type) == 0) return (file_read_error(info, type)); if (msg_verbose) diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c index 19e187384..cef245713 100644 --- a/postfix/src/postalias/postalias.c +++ b/postfix/src/postalias/postalias.c @@ -398,9 +398,10 @@ static void postalias(char *map_type, char *path_name, int postalias_flags, * recoverable error. */ for (;;) { + /* 202606 Qualys+Mythos: don't swap 'offset' and 'whence'. */ if (dict_isjmp(mkmap->dict) != 0 && dict_setjmp(mkmap->dict) != 0 - && vstream_fseek(source_fp, SEEK_SET, 0) < 0) + && vstream_fseek(source_fp, 0, SEEK_SET) < 0) msg_fatal("seek %s: %m", VSTREAM_PATH(source_fp)); /* diff --git a/postfix/src/postdrop/postdrop.c b/postfix/src/postdrop/postdrop.c index 28c89748c..1ce06ed40 100644 --- a/postfix/src/postdrop/postdrop.c +++ b/postfix/src/postdrop/postdrop.c @@ -512,7 +512,7 @@ int main(int argc, char **argv) } if (rec_type == REC_TYPE_ERROR) msg_fatal("uid=%ld: malformed input", (long) uid); - if (strchr(*expected, rec_type) == 0) + if (rec_type == 0 || strchr(*expected, rec_type) == 0) msg_fatal("uid=%ld: unexpected record type: %d", (long) uid, rec_type); if (rec_type == **expected) expected++; diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c index cf97313f4..70a2164f5 100644 --- a/postfix/src/postmap/postmap.c +++ b/postfix/src/postmap/postmap.c @@ -487,9 +487,10 @@ static void postmap(char *map_type, char *path_name, int postmap_flags, * recoverable error. */ for (;;) { + /* 202606 Qualys+Mythos: don't swap 'offset' and 'whence'. */ if (dict_isjmp(mkmap->dict) != 0 && dict_setjmp(mkmap->dict) != 0 - && vstream_fseek(source_fp, SEEK_SET, 0) < 0) + && vstream_fseek(source_fp, 0, SEEK_SET) < 0) msg_fatal("seek %s: %m", VSTREAM_PATH(source_fp)); /* diff --git a/postfix/src/postqueue/postqueue.c b/postfix/src/postqueue/postqueue.c index ecfe344d5..041a50ffe 100644 --- a/postfix/src/postqueue/postqueue.c +++ b/postfix/src/postqueue/postqueue.c @@ -431,10 +431,11 @@ static void show_queue(int mode) stat = vstream_pclose(showq); } argv_free(argv); - myfree(showq_path); + /* 202606 Qualys+Mythos: don't free() text before logging. */ if (stat != 0) msg_fatal_status(stat < 0 ? EX_OSERR : EX_SOFTWARE, "Error running %s", showq_path); + myfree(showq_path); } /* diff --git a/postfix/src/smtp/smtp_chat.c b/postfix/src/smtp/smtp_chat.c index 81c63e478..347d1cc3f 100644 --- a/postfix/src/smtp/smtp_chat.c +++ b/postfix/src/smtp/smtp_chat.c @@ -413,7 +413,8 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session) if (three_digs != 0) { rdata.code = atoi(STR(session->buffer)); if (strchr("245", STR(session->buffer)[0]) != 0) { - for (cp = STR(session->buffer) + 4; *cp == ' '; cp++) + /* 202606 Qualys+Mythos: start loop immediately after 'ddd'. */ + for (cp = STR(session->buffer) + 3; *cp == ' '; cp++) /* void */ ; if ((len = dsn_valid(cp)) > 0 && *cp == *STR(session->buffer)) { vstring_strncpy(rdata.dsn_buf, cp, len); diff --git a/postfix/src/smtpd/smtpd_xforward.c b/postfix/src/smtpd/smtpd_xforward.c index 053d3779a..ae88ae08e 100644 --- a/postfix/src/smtpd/smtpd_xforward.c +++ b/postfix/src/smtpd/smtpd_xforward.c @@ -64,6 +64,8 @@ void smtpd_xforward_init(SMTPD_STATE *state) state->xforward.helo_name = 0; state->xforward.ident = 0; state->xforward.domain = 0; + /* 202606 Qualys+Mythos: future proofing. */ + state->xforward.rfc_addr = 0; } /* smtpd_xforward_preset - set xforward attributes to "unknown" */ diff --git a/postfix/src/tls/tls_dane.c b/postfix/src/tls/tls_dane.c index b5d48ba29..49d1925db 100644 --- a/postfix/src/tls/tls_dane.c +++ b/postfix/src/tls/tls_dane.c @@ -447,7 +447,8 @@ void tls_dane_add_fpt_digests(TLS_DANE *dane, int pkey_only, } raw = vstring_alloc(ilen / 2); if (hex_decode_opt(raw, cp, ilen, HEX_DECODE_FLAG_ALLOW_COLON) == 0) { - myfree(raw); + /* 202606 Qualys+Mythos: vstring_free(), not myfree(). */ + vstring_free(raw); msg_warn("malformed fingerprint value: %.384s", values->argv[i]); continue; } diff --git a/postfix/src/tls/tls_scache.c b/postfix/src/tls/tls_scache.c index cf722ee7e..3896e7cb5 100644 --- a/postfix/src/tls/tls_scache.c +++ b/postfix/src/tls/tls_scache.c @@ -255,8 +255,8 @@ static int tls_scache_decode(TLS_SCACHE *cp, const char *cache_id, #define FREE_AND_RETURN(ptr, x) { vstring_free(ptr); return (x); } bin_data = vstring_alloc(hex_data_len / 2 + 1); - if (hex_decode_opt(bin_data, hex_data, hex_data_len, - HEX_DECODE_FLAG_ALLOW_COLON) == 0) { + /* 202606 Qualys+Mythos: disallow ':', enforce hex_encode() format. */ + if (hex_decode(bin_data, hex_data, hex_data_len) == 0) { msg_warn("%s TLS cache: malformed entry for %s: %.100s", cp->cache_label, cache_id, hex_data); FREE_AND_RETURN(bin_data, 0); diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c index afe6594e0..85705c609 100644 --- a/postfix/src/util/dict.c +++ b/postfix/src/util/dict.c @@ -688,6 +688,7 @@ static const NAME_MASK dict_mask[] = { "utf8_request", DICT_FLAG_UTF8_REQUEST, /* request UTF-8 activation */ "utf8_active", DICT_FLAG_UTF8_ACTIVE, /* UTF-8 is activated */ "src_rhs_is_file", DICT_FLAG_SRC_RHS_IS_FILE, /* value from file */ + "surrogate", DICT_FLAG_SURROGATE, /* surrogate dictionary */ 0, }; diff --git a/postfix/src/util/dict.h b/postfix/src/util/dict.h index 4a39170c5..3c3e8665e 100644 --- a/postfix/src/util/dict.h +++ b/postfix/src/util/dict.h @@ -133,7 +133,7 @@ extern void dict_free(DICT *); #define DICT_FLAG_UTF8_ACTIVE (1<<20) /* UTF-8 proxy layer is present */ #define DICT_FLAG_SRC_RHS_IS_FILE \ (1<<21) /* Map source RHS is a file */ -#define DICT_FLAG_SURROGATE (1<22) /* This is a surrogate dictionary */ +#define DICT_FLAG_SURROGATE (1<<22) /* This is a surrogate dictionary */ #define DICT_FLAG_UTF8_MASK (DICT_FLAG_UTF8_REQUEST) diff --git a/postfix/src/util/sys_compat.c b/postfix/src/util/sys_compat.c index a28deacdf..9d7c77beb 100644 --- a/postfix/src/util/sys_compat.c +++ b/postfix/src/util/sys_compat.c @@ -95,7 +95,8 @@ const char *strerror(int err) vstring_sprintf(buf, "Unknown error %d", err); return (vstring_str(buf)); } else { - return (sys_errlist[errno]); + /* 202606 Qualys+Mythos: use err, not errno. */ + return (sys_errlist[err]); } } diff --git a/postfix/src/util/vstring.c b/postfix/src/util/vstring.c index a1de4f18e..a43a855dc 100644 --- a/postfix/src/util/vstring.c +++ b/postfix/src/util/vstring.c @@ -612,7 +612,8 @@ VSTRING *vstring_import(char *str) vp->vbuf.flags = 0; vp->vbuf.len = 0; vp->vbuf.data = (unsigned char *) str; - vp->vbuf.len = len + 1; + /* 202606 Qualys+Mythos: do not count the null terminator. */ + vp->vbuf.len = len; VSTRING_AT_OFFSET(vp, len); vp->vbuf.get_ready = vstring_buf_get_ready; vp->vbuf.put_ready = vstring_buf_put_ready;