]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.12-20260709
authorWietse Z Venema <wietse@porcupine.org>
Mon, 6 Jul 2026 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Mon, 13 Jul 2026 15:52:24 +0000 (01:52 +1000)
14 files changed:
postfix/HISTORY
postfix/src/pickup/pickup.c
postfix/src/postalias/postalias.c
postfix/src/postdrop/postdrop.c
postfix/src/postmap/postmap.c
postfix/src/postqueue/postqueue.c
postfix/src/smtp/smtp_chat.c
postfix/src/smtpd/smtpd_xforward.c
postfix/src/tls/tls_dane.c
postfix/src/tls/tls_scache.c
postfix/src/util/dict.c
postfix/src/util/dict.h
postfix/src/util/sys_compat.c
postfix/src/util/vstring.c

index fc597d9940ad80fa5aadd7389a9c9242aa654dae..c22b0b2f793f3552a554a9128af56d4402878e69 100644 (file)
@@ -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.
index 390329d1eabdb668646198ffe513b2cbad8125fd..fa08ad038a23e05fbcec01974b981e42eaa86fe3 100644 (file)
@@ -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)
index 19e187384f858900f9577359b804895220de3490..cef245713fc347e39d9969e9e421de1d00aad316 100644 (file)
@@ -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));
 
        /*
index 28c89748c5f7106a3b09f271c6ad23c700d707a7..1ce06ed40ea3bb3b1d8fa020257abe6014415211 100644 (file)
@@ -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++;
index cf97313f450df7869ee13c663a91fdafa59fedc0..70a2164f5e97f22919adbd3d647624e8935b9733 100644 (file)
@@ -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));
 
        /*
index ecfe344d55a39540732c83ca7702f8e69a13d89b..041a50ffe757eeebca7b8154ec38e7ff7df33ce4 100644 (file)
@@ -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);
     }
 
     /*
index 81c63e478a25d18cd69b9f1f507c2a1e5c47f506..347d1cc3f2e60ec5483a5d0ff7a78ef66dae804a 100644 (file)
@@ -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);
index 053d3779a996eaeb6d9bff4f86811410c42ccb4f..ae88ae08e0b32a59f031587c662633026f4a0b56 100644 (file)
@@ -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" */
index b5d48ba2907bc62364f56da00d35681d887623c1..49d1925db8f25e1a9ac8e39c6fda69f309739bbb 100644 (file)
@@ -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;
        }
index cf722ee7e56188cfc90b0d41aba245ef68680573..3896e7cb54818f22784dbe9c25e10419fb5c7d8d 100644 (file)
@@ -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);
index afe6594e068499a6b327d007290d5aa9f6a78ec6..85705c609bc3b6193224628d9a5fb2d0c6fc31e8 100644 (file)
@@ -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,
 };
 
index 4a39170c572bd693eeafa1e503ff2755a4a824bf..3c3e8665e7a319899200bc2a4e05b3ab297def9f 100644 (file)
@@ -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)
 
index a28deacdf8db3ddb55c4866ec4dbdb95b9ee57b6..9d7c77beb1a87a4c033854d0c1329769035430d1 100644 (file)
@@ -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]);
     }
 }
 
index a1de4f18e2dbdb5c0f8cb90f84ee61692095edd9..a43a855dcc7929e20a27baa023ed0dbfdd126b4d 100644 (file)
@@ -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;