Vulnerability: smtp_mailaddr in smtp_session.c in OpenSMTPD 6.6, as used in OpenBSD 6.6 and other products, allows remote attackers to execute arbitrary commands as root via a crafted SMTP session, as demonstrated by shell metacharacters in a MAIL FROM field. This affects the "uncommented" default configuration. The issue exists because of an incorrect return value upon failure of input validation.
Vulnerability ID: CVE-2020-7247
CWE: CWE-78
Severity score: 10
Project: https://github.com/openbsd/src
Published: 2020-01-29
File: usr.sbin/smtpd/smtp_session.c
Commit message: Fix a security vulnerability discovered by Qualys which can lead to a
privileges escalation on mbox deliveries and unprivileged code execution
on lmtp deliveries, due to a logic issue causing a sanity check to be
missed.

ok eric@, millert@
Commit author: gilles

Vulnerable version (before fix):
 /*	$OpenBSD: smtp_session.c,v 1.421 2020/01/08 00:05:38 gilles Exp $	*/  /*  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> smtp_mailaddr(struct mailaddr *maddr, char *line, int mailfrom, char **args, 		memmove(maddr->user, p, strlen(p) + 1); 	}  	if (!valid_localpart(maddr->user) || 	    !valid_domainpart(maddr->domain)) { 		/* accept empty return-path in MAIL FROM, required for bounces */ 		if (mailfrom && maddr->user[0] == '\0' && maddr->domain[0] == '\0') 			return (1);  		/* no user-part, reject */ 		if (maddr->user[0] == '\0') 			return (0);  		/* no domain, local user */ 		if (maddr->domain[0] == '\0') { 			(void)strlcpy(maddr->domain, domain, 			    sizeof(maddr->domain)); 			return (1); 		} 		return (0); 	}  	return (1); } 

Fixed version (after fix):
 /*	$OpenBSD: smtp_session.c,v 1.422 2020/01/28 21:35:00 gilles Exp $	*/  /*  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> smtp_mailaddr(struct mailaddr *maddr, char *line, int mailfrom, char **args, 		memmove(maddr->user, p, strlen(p) + 1); 	}  	/* accept empty return-path in MAIL FROM, required for bounces */ 	if (mailfrom && maddr->user[0] == '\0' && maddr->domain[0] == '\0') 		return (1);  	/* no or invalid user-part, reject */ 	if (maddr->user[0] == '\0' || !valid_localpart(maddr->user)) 		return (0);  	/* no domain part, local user */ 	if (maddr->domain[0] == '\0') { 		(void)strlcpy(maddr->domain, domain, 			sizeof(maddr->domain)); 	}  	if (!valid_domainpart(maddr->domain)) 		return (0);  	return (1); } 

Patch:
patch: @@ -1,4 +1,4 @@
-/*	$OpenBSD: smtp_session.c,v 1.421 2020/01/08 00:05:38 gilles Exp $	*/
+/*	$OpenBSD: smtp_session.c,v 1.422 2020/01/28 21:35:00 gilles Exp $	*/
 
 /*
  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -2236,25 +2236,23 @@ smtp_mailaddr(struct mailaddr *maddr, char *line, int mailfrom, char **args,
 		memmove(maddr->user, p, strlen(p) + 1);
 	}
 
-	if (!valid_localpart(maddr->user) ||
-	    !valid_domainpart(maddr->domain)) {
-		/* accept empty return-path in MAIL FROM, required for bounces */
-		if (mailfrom && maddr->user[0] == '\0' && maddr->domain[0] == '\0')
-			return (1);
+	/* accept empty return-path in MAIL FROM, required for bounces */
+	if (mailfrom && maddr->user[0] == '\0' && maddr->domain[0] == '\0')
+		return (1);
 
-		/* no user-part, reject */
-		if (maddr->user[0] == '\0')
-			return (0);
-
-		/* no domain, local user */
-		if (maddr->domain[0] == '\0') {
-			(void)strlcpy(maddr->domain, domain,
-			    sizeof(maddr->domain));
-			return (1);
-		}
+	/* no or invalid user-part, reject */
+	if (maddr->user[0] == '\0' || !valid_localpart(maddr->user))
 		return (0);
+
+	/* no domain part, local user */
+	if (maddr->domain[0] == '\0') {
+		(void)strlcpy(maddr->domain, domain,
+			sizeof(maddr->domain));
 	}
 
+	if (!valid_domainpart(maddr->domain))
+		return (0);
+
 	return (1);
 }
path: usr.sbin/smtpd/smtp_session.c