From a6596ec37a4892e1d9c2498ecbfc4b8e6be5156a Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Fri, 22 Dec 2023 00:00:00 -0500 Subject: [PATCH] postfix-3.6.13 --- Upstream-Status: Backport from [https://launchpad.net/ubuntu/+source/postfix/3.6.4-1ubuntu1.3] CVE: CVE-2023-51764 Signed-off-by: Ashish Sharma man/man5/postconf.5 | 55 +++++++++++++++++++++++++++++++++++++++++++++++ man/man8/smtpd.8 | 9 +++++++ mantools/postlink | 2 + proto/postconf.proto | 52 ++++++++++++++++++++++++++++++++++++++++++++ src/global/mail_params.h | 11 ++++++++- src/global/smtp_stream.c | 14 +++++++++++ src/global/smtp_stream.h | 2 + src/smtpd/smtpd.c | 42 +++++++++++++++++++++++++++++++++++ 8 files changed, 185 insertions(+), 2 deletions(-) --- a/man/man5/postconf.5 +++ b/man/man5/postconf.5 @@ -10412,6 +10412,61 @@ parameter $name expansion. .PP This feature is available in Postfix 2.0 and later. +.SH smtpd_forbid_bare_newline (default: Postfix < 3.9: no) +Reply with "Error: bare received" and disconnect +when a remote SMTP client sends a line ending in , violating +the RFC 5321 requirement that lines must end in . +This feature is disbled by default with Postfix < 3.9. Use +smtpd_forbid_bare_newline_exclusions to exclude non\-standard clients +such as netcat. Specify "smtpd_forbid_bare_newline = no" to disable +(not recommended for an Internet\-connected MTA). +.PP +See +https://www.postfix.org/smtp\-smuggling.html for details. +.PP +Example: +.sp +.in +4 +.nf +.na +.ft C +# Disconnect remote SMTP clients that send bare newlines, but allow +# local clients with non\-standard SMTP implementations such as netcat, +# fax machines, or load balancer health checks. +# +smtpd_forbid_bare_newline = yes +smtpd_forbid_bare_newline_exclusions = $mynetworks +.fi +.ad +.ft R +.in -4 +.PP +This feature is available in Postfix >= 3.9, 3.8.4, 3.7.9, +3.6.13, and 3.5.23. +.SH smtpd_forbid_bare_newline_exclusions (default: $mynetworks) +Exclude the specified clients from smtpd_forbid_bare_newline +enforcement. It uses the same syntax and parent\-domain matching +behavior as mynetworks. +.PP +Example: +.sp +.in +4 +.nf +.na +.ft C +# Disconnect remote SMTP clients that send bare newlines, but allow +# local clients with non\-standard SMTP implementations such as netcat, +# fax machines, or load balancer health checks. +# +smtpd_forbid_bare_newline = yes +smtpd_forbid_bare_newline_exclusions = $mynetworks +.fi +.ad +.ft R +.in -4 +.PP +This feature is available in Postfix >= 3.9, 3.8.4, 3.7.9, +3.6.13, and 3.5.23. .SH smtpd_forbidden_commands (default: CONNECT, GET, POST) List of commands that cause the Postfix SMTP server to immediately terminate the session with a 221 code. This can be used to disconnect --- a/man/man8/smtpd.8 +++ b/man/man8/smtpd.8 @@ -808,6 +808,15 @@ The maximal number of AUTH commands that any client is allowed to send to this service per time unit, regardless of whether or not Postfix actually accepts those commands. +.PP +Available in Postfix 3.9, 3.8.4, 3.7.9, 3.6.13, 3.5.23 and later: +.IP "\fBsmtpd_forbid_bare_newline (Postfix < 3.9: no)\fR" +Reply with "Error: bare received" and disconnect +when a remote SMTP client sends a line ending in , violating +the RFC 5321 requirement that lines must end in . +.IP "\fBsmtpd_forbid_bare_newline_exclusions ($mynetworks)\fR" +Exclude the specified clients from smtpd_forbid_bare_newline +enforcement. .SH "TARPIT CONTROLS" .na .nf --- a/mantools/postlink +++ b/mantools/postlink @@ -547,6 +547,8 @@ s;\bsmtpd_error_sleep_time\b;$&;g; s;\bsmtpd_etrn_restrictions\b;$&;g; s;\bsmtpd_expansion_filter\b;$&;g; + s;\bsmtpd_for[-]*\n*[ ]*bid_bare_newline\b;$&;g; + s;\bsmtpd_for[-]*\n*[ ]*bid_bare_newline_exclusions\b;$&;g; s;\bsmtpd_for[-]*\n*[ ]*bidden_commands\b;$&;g; s;\bsmtpd_hard_error_limit\b;$&;g; s;\bsmtpd_helo_required\b;$&;g; --- a/proto/postconf.proto +++ b/proto/postconf.proto @@ -18058,3 +18058,55 @@ name or port number.

This feature is available in Postfix 3.6 and later.

+ +%PARAM smtpd_forbid_bare_newline Postfix < 3.9: no + +

Reply with "Error: bare <LF> received" and disconnect +when a remote SMTP client sends a line ending in <LF>, violating +the RFC 5321 requirement that lines must end in <CR><LF>. +This feature is disbled by default with Postfix < 3.9. Use +smtpd_forbid_bare_newline_exclusions to exclude non-standard clients +such as netcat. Specify "smtpd_forbid_bare_newline = no" to disable +(not recommended for an Internet-connected MTA).

+ +

See +https://www.postfix.org/smtp-smuggling.html for details. + +

Example:

+ +
+
+# Disconnect remote SMTP clients that send bare newlines, but allow
+# local clients with non-standard SMTP implementations such as netcat,
+# fax machines, or load balancer health checks.
+#
+smtpd_forbid_bare_newline = yes
+smtpd_forbid_bare_newline_exclusions = $mynetworks
+
+
+ +

This feature is available in Postfix ≥ 3.9, 3.8.4, 3.7.9, +3.6.13, and 3.5.23.

+ +%PARAM smtpd_forbid_bare_newline_exclusions $mynetworks + +

Exclude the specified clients from smtpd_forbid_bare_newline +enforcement. It uses the same syntax and parent-domain matching +behavior as mynetworks.

+ +

Example:

+ +
+
+# Disconnect remote SMTP clients that send bare newlines, but allow
+# local clients with non-standard SMTP implementations such as netcat,
+# fax machines, or load balancer health checks.
+#
+smtpd_forbid_bare_newline = yes
+smtpd_forbid_bare_newline_exclusions = $mynetworks
+
+
+ +

This feature is available in Postfix ≥ 3.9, 3.8.4, 3.7.9, +3.6.13, and 3.5.23.

+ --- a/src/global/mail_params.h +++ b/src/global/mail_params.h @@ -4170,7 +4170,16 @@ extern char *var_smtpd_dns_re_filter; /* - * Share TLS sessions through tlproxy(8). + * Backwards compatibility. + */ +#define VAR_SMTPD_FORBID_BARE_LF "smtpd_forbid_bare_newline" +#define DEF_SMTPD_FORBID_BARE_LF 0 + +#define VAR_SMTPD_FORBID_BARE_LF_EXCL "smtpd_forbid_bare_newline_exclusions" +#define DEF_SMTPD_FORBID_BARE_LF_EXCL "$" VAR_MYNETWORKS + + /* + * Share TLS sessions through tlsproxy(8). */ #define VAR_SMTP_TLS_CONN_REUSE "smtp_tls_connection_reuse" #define DEF_SMTP_TLS_CONN_REUSE 0 --- a/src/global/smtp_stream.c +++ b/src/global/smtp_stream.c @@ -50,6 +50,8 @@ /* VSTREAM *stream; /* char *format; /* va_list ap; +/* +/* int smtp_forbid_bare_lf; /* AUXILIARY API /* int smtp_get_noexcept(vp, stream, maxlen, flags) /* VSTRING *vp; @@ -124,11 +126,16 @@ /* smtp_vprintf() is the machine underneath smtp_printf(). /* /* smtp_get_noexcept() implements the subset of smtp_get() -/* without timeouts and without making long jumps. Instead, +/* without long jumps for timeout or EOF errors. Instead, /* query the stream status with vstream_feof() etc. +/* This function will make a VSTREAM long jump (error code +/* SMTP_ERR_LF) when rejecting input with a bare newline byte. /* /* smtp_timeout_setup() is a backwards-compatibility interface /* for programs that don't require per-record deadline support. +/* +/* smtp_forbid_bare_lf controls whether smtp_get_noexcept() +/* will reject input with a bare newline byte. /* DIAGNOSTICS /* .fi /* .ad @@ -201,6 +208,8 @@ #include "smtp_stream.h" +int smtp_forbid_bare_lf; + /* smtp_timeout_reset - reset per-stream error flags, restart deadline timer */ static void smtp_timeout_reset(VSTREAM *stream) @@ -404,6 +413,9 @@ */ case '\n': vstring_truncate(vp, VSTRING_LEN(vp) - 1); + if (smtp_forbid_bare_lf + && (VSTRING_LEN(vp) == 0 || vstring_end(vp)[-1] != '\r')) + vstream_longjmp(stream, SMTP_ERR_LF); while (VSTRING_LEN(vp) > 0 && vstring_end(vp)[-1] == '\r') vstring_truncate(vp, VSTRING_LEN(vp) - 1); VSTRING_TERMINATE(vp); --- a/src/global/smtp_stream.h +++ b/src/global/smtp_stream.h @@ -32,6 +32,7 @@ #define SMTP_ERR_QUIET 3 /* silent cleanup (application) */ #define SMTP_ERR_NONE 4 /* non-error case */ #define SMTP_ERR_DATA 5 /* application data error */ +#define SMTP_ERR_LF 6 /* bare protocol error */ extern void smtp_stream_setup(VSTREAM *, int, int); extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...); @@ -43,6 +44,7 @@ extern void smtp_fwrite(const char *, ssize_t len, VSTREAM *); extern void smtp_fread_buf(VSTRING *, ssize_t len, VSTREAM *); extern void smtp_fputc(int, VSTREAM *); +extern int smtp_forbid_bare_lf; extern void smtp_vprintf(VSTREAM *, const char *, va_list); --- a/src/smtpd/smtpd.c +++ b/src/smtpd/smtpd.c @@ -762,6 +762,15 @@ /* The maximal number of AUTH commands that any client is allowed to /* send to this service per time unit, regardless of whether or not /* Postfix actually accepts those commands. +/* .PP +/* Available in Postfix 3.9, 3.8.4, 3.7.9, 3.6.13, 3.5.23 and later: +/* .IP "\fBsmtpd_forbid_bare_newline (Postfix < 3.9: no)\fR" +/* Reply with "Error: bare received" and disconnect +/* when a remote SMTP client sends a line ending in , violating +/* the RFC 5321 requirement that lines must end in . +/* .IP "\fBsmtpd_forbid_bare_newline_exclusions ($mynetworks)\fR" +/* Exclude the specified clients from smtpd_forbid_bare_newline +/* enforcement. /* TARPIT CONTROLS /* .ad /* .fi @@ -1467,6 +1476,10 @@ int var_smtpd_uproxy_tmout; bool var_relay_before_rcpt_checks; +bool var_smtpd_forbid_bare_lf; +char *var_smtpd_forbid_bare_lf_excl; +static NAMADR_LIST *bare_lf_excl; + /* * Silly little macros. */ @@ -1541,6 +1554,7 @@ #define REASON_TIMEOUT "timeout" #define REASON_LOST_CONNECTION "lost connection" #define REASON_ERROR_LIMIT "too many errors" +#define REASON_BARE_LF "bare received" #ifdef USE_TLS @@ -3967,6 +3981,7 @@ */ done = 0; do { + int payload_err; /* * Do not skip the smtp_fread_buf() call if read_len == 0. We still @@ -3980,6 +3995,10 @@ smtp_fread_buf(state->buffer, read_len, state->client); state->bdat_get_stream = vstream_memreopen( state->bdat_get_stream, state->buffer, O_RDONLY); + vstream_control(state->bdat_get_stream, CA_VSTREAM_CTL_EXCEPT, + CA_VSTREAM_CTL_END); + if ((payload_err = vstream_setjmp(state->bdat_get_stream)) != 0) + vstream_longjmp(state->client, payload_err); /* * Read lines from the fragment. The last line may continue in the @@ -4655,6 +4674,9 @@ */ xclient_allowed = namadr_list_match(xclient_hosts, state->name, state->addr); + smtp_forbid_bare_lf = SMTPD_STAND_ALONE((state)) == 0 + && var_smtpd_forbid_bare_lf + && !namadr_list_match(bare_lf_excl, state->name, state->addr); /* NOT: tls_reset() */ if (got_helo == 0) helo_reset(state); @@ -5446,6 +5468,13 @@ var_myhostname); break; + case SMTP_ERR_LF: + state->reason = REASON_BARE_LF; + if (vstream_setjmp(state->client) == 0) + smtpd_chat_reply(state, "521 5.5.2 %s Error: bare received", + var_myhostname); + break; + case 0: /* @@ -5995,6 +6024,13 @@ namadr_list_match(xforward_hosts, state.name, state.addr); /* + * Enforce strict SMTP line endings, with compatibility exclusions. + */ + smtp_forbid_bare_lf = SMTPD_STAND_ALONE((&state)) == 0 + && var_smtpd_forbid_bare_lf + && !namadr_list_match(bare_lf_excl, state.name, state.addr); + + /* * See if we need to turn on verbose logging for this client. */ debug_peer_check(state.name, state.addr); @@ -6055,6 +6091,10 @@ hogger_list = namadr_list_init(VAR_SMTPD_HOGGERS, MATCH_FLAG_RETURN | match_parent_style(VAR_SMTPD_HOGGERS), var_smtpd_hoggers); + bare_lf_excl = namadr_list_init(VAR_SMTPD_FORBID_BARE_LF_EXCL, + MATCH_FLAG_RETURN + | match_parent_style(VAR_MYNETWORKS), + var_smtpd_forbid_bare_lf_excl); /* * Open maps before dropping privileges so we can read passwords etc. @@ -6412,6 +6452,7 @@ VAR_SMTPD_PEERNAME_LOOKUP, DEF_SMTPD_PEERNAME_LOOKUP, &var_smtpd_peername_lookup, VAR_SMTPD_DELAY_OPEN, DEF_SMTPD_DELAY_OPEN, &var_smtpd_delay_open, VAR_SMTPD_CLIENT_PORT_LOG, DEF_SMTPD_CLIENT_PORT_LOG, &var_smtpd_client_port_log, + VAR_SMTPD_FORBID_BARE_LF, DEF_SMTPD_FORBID_BARE_LF, &var_smtpd_forbid_bare_lf, 0, }; static const CONFIG_NBOOL_TABLE nbool_table[] = { @@ -6527,6 +6568,7 @@ VAR_SMTPD_POLICY_CONTEXT, DEF_SMTPD_POLICY_CONTEXT, &var_smtpd_policy_context, 0, 0, VAR_SMTPD_DNS_RE_FILTER, DEF_SMTPD_DNS_RE_FILTER, &var_smtpd_dns_re_filter, 0, 0, VAR_SMTPD_REJ_FTR_MAPS, DEF_SMTPD_REJ_FTR_MAPS, &var_smtpd_rej_ftr_maps, 0, 0, + VAR_SMTPD_FORBID_BARE_LF_EXCL, DEF_SMTPD_FORBID_BARE_LF_EXCL, &var_smtpd_forbid_bare_lf_excl, 0, 0, 0, }; static const CONFIG_RAW_TABLE raw_table[] = {