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);

Reply via email to