From: Wietse Z Venema Date: Mon, 13 Jul 2026 05:00:00 +0000 (-0500) Subject: postfix-3.12-20260713 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=525073fd1e9e35278bde9ed0786e7cfe98415ab0;p=thirdparty%2Fpostfix.git postfix-3.12-20260713 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 0445d7a1a..92aa81bcc 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -31688,6 +31688,35 @@ Apologies for any names omitted. bytes of unused VSTRING buffer space. Suggested by Qualys, assisted by Claude Mythos Preview. File: qmqpd.c. +20260713 + + Read after free (no privilege escalation) in debug logging + in dict_tcp.c, xsasl_dovecot_server.c, master_wakeup.c + (defect introduced: Postfix 2.2, date: 20050117). Reported + by Qualys, assisted by Claude Mythos Preview. File: + util/inet_connect.c. + + Code hygiene: in a NIS+ lookup table name, enforce the '%s' + substitution syntax (defect introduced: Postfix 2.2, date: + 20041018). NIS+ support was removed with Solaris 10. + Suggested by Qualys, assisted by Claude Mythos Preview. + File: dict_nisplus.c. + + Code hygiene: in clean_ascii_cntrl_space(), don't assume + that input will always be null-terminated. Reported by + Qualys, assisted by Claude Mythos Preview. File: + clean_ascii_cntrl_space.c. + + Code hygiene: in tlsproxy(8), initialize state->ssl_last_err + as SSL_ERROR_NONE, instead of the mymalloc() default value + (-1). Suggested by Qualys, assisted by Claude Mythos + Preview. File: tlsproxy_state.c. + + Bug (defect introduced: Postfix 2.8, date: 20110102): while + tearing down a TLS session, tlsproxy(8) closed the same + file descriptor twice (without any adverse effect). Files: + nbbio.[hc]. + TODO Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index b516b12cb..7e43f5231 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20260710" +#define MAIL_RELEASE_DATE "20260713" #define MAIL_VERSION_NUMBER "3.12" #ifdef SNAPSHOT diff --git a/postfix/src/tlsproxy/tlsproxy_state.c b/postfix/src/tlsproxy/tlsproxy_state.c index a82106683..d62b61405 100644 --- a/postfix/src/tlsproxy/tlsproxy_state.c +++ b/postfix/src/tlsproxy/tlsproxy_state.c @@ -124,6 +124,8 @@ TLSP_STATE *tlsp_state_create(const char *service, state->client_params = 0; state->client_init_props = 0; state->client_start_props = 0; + /* 200606 Qualys+Mythos: explicit initialization. */ + state->ssl_last_err = SSL_ERROR_NONE; return (state); } diff --git a/postfix/src/util/clean_ascii_cntrl_space.c b/postfix/src/util/clean_ascii_cntrl_space.c index 81f2ee53f..8e7045f19 100644 --- a/postfix/src/util/clean_ascii_cntrl_space.c +++ b/postfix/src/util/clean_ascii_cntrl_space.c @@ -71,7 +71,8 @@ char *clean_ascii_cntrl_space(VSTRING *result, const char *str, ssize_t len) ch = *(unsigned char *) cp; if (ISCNTRL(ch)) ch = ' '; - if (ch == ' ' && (prev_ch == ' ' || cp[1] == 0)) + /* 202606 Qualys_Mythos: don't assume input is null-terminated. */ + if (ch == ' ' && (prev_ch == ' ' || cp >= str_end - 1)) continue; VSTRING_ADDCH(result, ch); prev_ch = ch; diff --git a/postfix/src/util/dict_nisplus.c b/postfix/src/util/dict_nisplus.c index e14cdd0c4..d83a6253c 100644 --- a/postfix/src/util/dict_nisplus.c +++ b/postfix/src/util/dict_nisplus.c @@ -252,6 +252,7 @@ DICT *dict_nisplus_open(const char *map, int open_flags, int dict_flags) const char *myname = "dict_nisplus_open"; DICT_NISPLUS *dict_nisplus; char *col_field; + const char *cp; /* * Sanity check. @@ -284,7 +285,12 @@ DICT *dict_nisplus_open(const char *map, int open_flags, int dict_flags) * other attributes must specify fixed values. The reason for using ';' * is that the comma character is special in main.cf. When no column * number is given at the end of the map name, we use a default column. + * + * 2026506 Qualys+Mythos: enforce template substution syntax. */ + if ((cp = strchr(map, '%')) == 0 || strncmp(cp, "%s", 2) != 0 + || strchr(cp + 2, '%') != 0) + msg_fatal("bad '%%' substitution syntax in NIS+ map name: %s", map); dict_nisplus->template = mystrdup(map); translit(dict_nisplus->template, ";", ","); if ((col_field = strstr(dict_nisplus->template, ".:")) != 0) { diff --git a/postfix/src/util/inet_connect.c b/postfix/src/util/inet_connect.c index 02a3962ad..b1a09c334 100644 --- a/postfix/src/util/inet_connect.c +++ b/postfix/src/util/inet_connect.c @@ -115,8 +115,9 @@ int inet_connect(const char *addr, int block_mode, int timeout) * Safety net. */ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { + /* 202606 Qualys+Mythos: myfree() above frees 'host' and 'port'. */ msg_info("skipping address family %d for host %s", - res->ai_family, host); + res->ai_family, addr); continue; } found++; diff --git a/postfix/src/util/nbbio.c b/postfix/src/util/nbbio.c index e9ccc3878..f3666baf3 100644 --- a/postfix/src/util/nbbio.c +++ b/postfix/src/util/nbbio.c @@ -31,6 +31,9 @@ /* NBBIO *np; /* int timeout; /* +/* void nbbio_own_fd(np) +/* NBBIO *np; +/* /* int NBBIO_ACTIVE_FLAGS(np) /* NBBIO *np; /* @@ -71,8 +74,8 @@ /* with the application-specified context. /* /* nbbio_free() terminates any pseudothreads associated with -/* the named buffer pair, closes the stream, and destroys the -/* buffer pair. +/* the named buffer pair, closes the stream if it is owned, and +/* destroys the buffer pair. /* /* nbbio_enable_read() enables a read pseudothread (if one /* does not already exist) for the named buffer pair, and @@ -97,6 +100,8 @@ /* buffer liveness. It is no error to call this function while /* no read/write pseudothread is enabled. /* +/* nbbio_own_fd() makes the NBBIO owner of the file descriptor. +/* /* NBBIO_ERROR_FLAGS() returns the error flags for the named buffer /* pair: zero or more of NBBIO_FLAG_EOF (read EOF), NBBIO_FLAG_ERROR /* (read/write error) or NBBIO_FLAG_TIMEOUT (time limit @@ -374,7 +379,9 @@ NBBIO *nbbio_create(int fd, ssize_t bufsize, const char *label, void nbbio_free(NBBIO *np) { nbbio_disable_readwrite(np); - (void) close(np->fd); + /* 202606 Qualys+Mythos: close decriptor only if owner. */ + if (np->flags & NBBIO_FLAG_OWN_FD) + (void) close(np->fd); myfree(np->label); myfree(np->read_buf); myfree(np->write_buf); diff --git a/postfix/src/util/nbbio.h b/postfix/src/util/nbbio.h index d1d2b0ef7..cb681acc4 100644 --- a/postfix/src/util/nbbio.h +++ b/postfix/src/util/nbbio.h @@ -41,6 +41,7 @@ typedef struct { #define NBBIO_FLAG_EOF (1<<2) #define NBBIO_FLAG_ERROR (1<<3) #define NBBIO_FLAG_TIMEOUT (1<<4) +#define NBBIO_FLAG_OWN_FD (1<<5) #define NBBIO_OP_NAME(np) \ (((np)->flags & NBBIO_FLAG_READ) ? "read" : \ @@ -64,6 +65,8 @@ typedef struct { #define NBBIO_ACTIVE_FLAGS(np) ((np)->flags & NBBIO_MASK_ACTIVE) #define NBBIO_ERROR_FLAGS(np) ((np)->flags & NBBIO_MASK_ERROR) +#define nbbio_own_fd(np) ((np)->flags |= NBBIO_FLAG_OWN_FD) + extern NBBIO *nbbio_create(int, ssize_t, const char *, NBBIO_ACTION, void *); extern void nbbio_free(NBBIO *); extern void nbbio_enable_read(NBBIO *, int);