On Fri, Mar 19, 2021 at 11:18:27AM -0400, Jaroslav Skarvada wrote: > 14. postfix-3.5.8/src/util/dict_inline.c:124: uninit_use_in_call: Using > uninitialized value "value" when calling "dict_file_to_b64". > 17. postfix-3.5.8/src/util/dict_inline.c:125: overwrite_var: Overwriting > "err" in "err = free_me = dict_file_get_error(dict)" leaks the storage that > "err" points to. > # 123| > # 124|-> if ((base64_buf = dict_file_to_b64(dict, value)) == 0) { > # 125|-> err = free_me = dict_file_get_error(dict); > # 126| break; > # 127| } > > I think it could call dict_file_to_b64 with uninitialized value.
Yes, when inline tables in the main.cf file are malformed in a particular way, this may not be handled correctly. Patch below. > 61. postfix-3.5.8/src/util/dict_inline.c:131:2: note: 2nd function call > argument is an uninitialized value > # dict->update(dict, vname, value); > # ^ ~~~~~ > # 129| } > # 130| /* No duplicate checks. See comments in dict_thash.c. */ > # 131|-> dict->update(dict, vname, value); > # 132| count += 1; > # 133| } Same dict_inline issue as above... > 7. postfix-3.5.8/src/global/haproxy_srvr.c:456: dereference: Dereferencing a > pointer that might be "NULL" "mystrtok(&cp, " \r")" when calling > "haproxy_srvr_parse_proto". > > # 454| else if (haproxy_srvr_parse_lit(NEXT_TOKEN, "PROXY", (char *) > 0) < 0) > # 455| err = "unexpected protocol header"; > # 456|-> else if (haproxy_srvr_parse_proto(NEXT_TOKEN, &addr_family) < 0) > # 457| err = "unsupported protocol type"; > # 458| else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_client_addr, > > I think for malformed input it could fail by calling strncasecmp with NULL. Yes, parse_proto is missing a NULL check. Patch below. > 1. postfix-3.5.8/src/tlsproxy/tlsproxy.c:1881:49: warning[-Wmissing-braces]: > missing braces around initializer > # static const CONFIG_STR_TABLE str_table[] = { > # ^ > # 1879| 0, > # 1880| }; > # 1881|-> static const CONFIG_STR_TABLE str_table[] = { > # 1882| VAR_TLSP_TLS_CHAIN_FILES, DEF_TLSP_TLS_CHAIN_FILES, > &var_tlsp_tls_chain_files, 0, 0, > # 1883| VAR_TLSP_TLS_CERT_FILE, DEF_TLSP_TLS_CERT_FILE, > &var_tlsp_tls_cert_file, 0, 0, > > I think it should have braces around table lines. There are multiple tables > with the same warning. The table content is correct as written, and I don't expect we'll be changing it. But if Wietse is inclined to rototill all the tables... > 2. postfix-3.5.8/src/smtp/smtp_session.c:200: var_compare_op: Comparing > "session->stream" to null implies that "session->stream" might be null. > 5. postfix-3.5.8/src/smtp/smtp_session.c:208: var_deref_model: Passing null > pointer "session->stream" to "tls_session_stop", which dereferences it. > # 206| tls_proxy_context_free(session->tls_context); > # 207| else > # 208|-> tls_client_stop(smtp_tls_ctx, session->stream, > # 209| var_smtp_starttls_tmout, 0, > session->tls_context); > # 210| } > > It's suspicious that there is the NULL check, but later it could fail on NULL > dereference. In that particular branch the stream is sure to be non-null. > 7. postfix-3.5.8/src/smtpd/smtpd.c:1712: var_compare_op: Comparing > "state->milters" to null implies that "state->milters" might be null. > 9. postfix-3.5.8/src/smtpd/smtpd.c:1727: var_deref_model: Passing "state" to > "mail_reset", which dereferences null "state->milters". > # 1725| helo_reset(state); > # 1726| chat_reset(state, var_smtpd_hist_thrsh); > # 1727|-> mail_reset(state); > # 1728| rcpt_reset(state); > # 1729| state->helo_name = mystrdup(printable(argv[1].strval, '?')); > > It's suspicious that there is the NULL check, but later it could fail on NULL > dereference. The flag that guards the milter dereference is only set when the milter pointer is not null. > 31. postfix-3.5.8/src/tls/tls_proxy_client_scan.c:335:9: note: Access to > field 'next' results in a dereference of a null pointer (loaded from variable > 'tp') > # if (tp->next) > # ^~ > # 333| static void tls_proxy_client_tlsa_free(TLS_TLSA *tp) > # 334| { > # 335|-> if (tp->next) > # 336| tls_proxy_client_tlsa_free(tp->next); > # 337| myfree(tp->mdalg); > 37. postfix-3.5.8/src/tls/tls_proxy_client_scan.c:324:9: note: Access to > field 'next' results in a dereference of a null pointer (loaded from variable > 'tp') > # if (tp->next) > # ^~ > # 322| static void tls_proxy_client_pkeys_free(TLS_PKEYS *tp) > # 323| { > # 324|-> if (tp->next) > # 325| tls_proxy_client_pkeys_free(tp->next); > # 326| if (tp->pkey) > 37. postfix-3.5.8/src/tls/tls_proxy_client_scan.c:313:9: note: Access to > field 'next' results in a dereference of a null pointer (loaded from variable > 'tp') > # if (tp->next) > # ^~ > # 311| static void tls_proxy_client_certs_free(TLS_CERTS *tp) > # 312| { > # 313|-> if (tp->next) > # 314| tls_proxy_client_certs_free(tp->next); > # 315| if (tp->cert) This code has been replaced in Postfix 3.6, patch for earlier versions below my signature. The NPE can only arise when internal communication protocols are interrupted midstream. > 88. postfix-3.5.8/src/global/maillog_client.c:256:10: note: Null pointer > passed to 2nd parameter expecting 'nonnull' > # if (setenv(POSTLOG_SERVICE_ENV, service_path, 1) < 0) > # ^ ~~~~~~~~~~~~ > # 254| msg_info("export %s=%s", POSTLOG_SERVICE_ENV, service_path); > # 255| #endif > # 256|-> if (setenv(POSTLOG_SERVICE_ENV, service_path, 1) < 0) > # 257| msg_fatal("setenv: %m"); > # 258| } This looks plausible, but I'm not sure what the right fix is. > 19. postfix-3.5.8/include/vstring.h:70:36: note: expanded from macro > 'vstring_str' > # #define vstring_str(vp) ((char *) (vp)->vbuf.data) > # ^~~~~~~~~~~~~~~ > # 72| vstring_sprintf(canon_name, "%s/%s", tag, argv0); > # 73| } > # 74|-> return (vstring_str(canon_name)); > # 75| } This is a non-problem, the first call always sets a non-null value, but I'm adding a harmless fallback, just in case argv[0] is NULL. ---------- Patch for Postfix 3.5 and 3.6 (perhaps also earlier versions?) --------- --- a/src/global/haproxy_srvr.c +++ b/src/global/haproxy_srvr.c @@ -201,6 +201,8 @@ static int haproxy_srvr_parse_proto(const char *str, int *addr_family) if (msg_verbose) msg_info("haproxy_srvr_parse: proto=%s", STR_OR_NULL(str)); + if (str == 0) + return (-1); #ifdef AF_INET6 if (strcasecmp(str, "TCP6") == 0) { if (strchr((char *) proto_info->sa_family_list, AF_INET6) != 0) { --- a/src/global/mail_task.c +++ b/src/global/mail_task.c @@ -71,5 +71,7 @@ const char *mail_task(const char *argv0) mail_conf_eval(DEF_SYSLOG_NAME); vstring_sprintf(canon_name, "%s/%s", tag, argv0); } - return (vstring_str(canon_name)); + if (canon_name) + return (vstring_str(canon_name)); + return ("unknown"); } --- a/src/util/dict_inline.c +++ b/src/util/dict_inline.c @@ -113,9 +113,11 @@ DICT *dict_inline_open(const char *name, int open_flags, int dict_flags) dict = dict_open3(DICT_TYPE_HT, name, open_flags, dict_flags); dict_type_override(dict, DICT_TYPE_INLINE); while ((nameval = mystrtokq(&cp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) { - if ((nameval[0] != CHARS_BRACE[0] - || (err = free_me = extpar(&nameval, CHARS_BRACE, EXTPAR_FLAG_STRIP)) == 0) - && (err = split_qnameval(nameval, &vname, &value)) != 0) + if (nameval[0] != CHARS_BRACE[0]) + err = free_me = extpar(&nameval, CHARS_BRACE, EXTPAR_FLAG_STRIP); + if (!err) + err = split_qnameval(nameval, &vname, &value); + if (err) break; if ((dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) != 0) { -- Viktor. ---------- Below patch for Postfix 3.5 only: ---------- --- a/postfix/src/tls/tls_proxy_client_scan.c +++ b/postfix/src/tls/tls_proxy_client_scan.c @@ -310,6 +310,8 @@ int tls_proxy_client_init_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, static void tls_proxy_client_certs_free(TLS_CERTS *tp) { + if (tp == 0) + return; if (tp->next) tls_proxy_client_certs_free(tp->next); if (tp->cert) @@ -321,6 +323,8 @@ static void tls_proxy_client_certs_free(TLS_CERTS *tp) static void tls_proxy_client_pkeys_free(TLS_PKEYS *tp) { + if (tp == 0) + return; if (tp->next) tls_proxy_client_pkeys_free(tp->next); if (tp->pkey) @@ -332,6 +336,8 @@ static void tls_proxy_client_pkeys_free(TLS_PKEYS *tp) static void tls_proxy_client_tlsa_free(TLS_TLSA *tp) { + if (tp == 0) + return; if (tp->next) tls_proxy_client_tlsa_free(tp->next); myfree(tp->mdalg);