From 98ccabf68e5b3f0a177bd1925581753d10041448 Mon Sep 17 00:00:00 2001
From: Simon Josefsson <simon@josefsson.org>
Date: Wed, 1 Sep 2021 09:09:50 +0200
Subject: [PATCH] ftp: check that PASV/LSPV addresses match.

* NEWS: Mention change.
* ftp/ftp.c (initconn): Validate returned addresses.

CVE: CVE-2021-40491

Upstream-Status: Backport
[https://git.savannah.gnu.org/cgit/inetutils.git/commit/?id=58cb043b190fd04effdaea7c9403416b436e50dd]

Signed-off-by: Yi Zhao <yi.zhao@windriver.com>
---
 NEWS      |  9 +++++++++
 ftp/ftp.c | 21 +++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/NEWS b/NEWS
index 7c5e62c..bd9a4da 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,15 @@ GNU inetutils NEWS -- history of user-visible changes.
 
 ** ftp
 
+The ftp client now validate addresses returned by PASV/LSPV responses,
+to make sure they match the server address.  Reported by ZeddYu Lu in
+<https://lists.gnu.org/archive/html/bug-inetutils/2021-06/msg00002.html>.
+
+Thanks to Luke Mewburn <lukem@netbsd.org> for discussion and fix to
+NetBSD code, we used a similar solution.
+
+** ftp
+
 Disable use of readline when environment variable TERM is unset or set
 to "dumb" (caused problems with Emacs AngeFTP on MacOS).  Thanks to
 Alex Bochannek for report, debugging and patch.
diff --git a/ftp/ftp.c b/ftp/ftp.c
index d21dbdd..7513539 100644
--- a/ftp/ftp.c
+++ b/ftp/ftp.c
@@ -1365,6 +1365,13 @@ initconn (void)
 		  uint32_t *pu32 = (uint32_t *) &data_addr_sa4->sin_addr.s_addr;
 		  pu32[0] = htonl ( (h[0] << 24) | (h[1] << 16) | (h[2] << 8) | h[3]);
 		}
+		if (data_addr_sa4->sin_addr.s_addr
+		    != ((struct sockaddr_in *) &hisctladdr)->sin_addr.s_addr)
+		  {
+		    printf ("Passive mode address mismatch.\n");
+		    (void) command ("ABOR");	/* Cancel any open connection.  */
+		    goto bad;
+		  }
 	    } /* LPSV IPv4 */
 	  else /* IPv6 */
 	    {
@@ -1395,6 +1402,13 @@ initconn (void)
 		  pu32[2] = htonl ( (h[8] << 24) | (h[9] << 16) | (h[10] << 8) | h[11]);
 		  pu32[3] = htonl ( (h[12] << 24) | (h[13] << 16) | (h[14] << 8) | h[15]);
 		}
+		if (data_addr_sa6->sin6_addr.s6_addr
+		    != ((struct sockaddr_in6 *) &hisctladdr)->sin6_addr.s6_addr)
+		  {
+		    printf ("Passive mode address mismatch.\n");
+		    (void) command ("ABOR");	/* Cancel any open connection.  */
+		    goto bad;
+		  }
 	    } /* LPSV IPv6 */
 	}
       else /* !EPSV && !LPSV */
@@ -1415,6 +1429,13 @@ initconn (void)
 			 | ((a2 & 0xff) << 8) | (a3 & 0xff) );
 	      data_addr_sa4->sin_port =
 		  htons (((p0 & 0xff) << 8) | (p1 & 0xff));
+	      if (data_addr_sa4->sin_addr.s_addr
+		  != ((struct sockaddr_in *) &hisctladdr)->sin_addr.s_addr)
+		{
+		  printf ("Passive mode address mismatch.\n");
+		  (void) command ("ABOR");	/* Cancel any open connection.  */
+		  goto bad;
+		}
 	    } /* PASV */
 	  else
 	    {
-- 
2.17.1

