From 29b251362e1839d7094993edbed8f9467069773f Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Mon, 25 Sep 2017 00:35:22 +0200
Subject: [PATCH] FTP: zero terminate the entry path even on bad input

... a single double quote could leave the entry path buffer without a zero
terminating byte. CVE-2017-1000254

Test 1152 added to verify.

Reported-by: Max Dymond
Bug: https://curl.haxx.se/docs/adv_20171004.html
---
 lib/ftp.c               |  7 ++++--
 tests/data/Makefile.inc |  1 +
 tests/data/test1152     | 61 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 2 deletions(-)
 create mode 100644 tests/data/test1152

Index: curl-7.19.7/lib/ftp.c
===================================================================
--- curl-7.19.7.orig/lib/ftp.c
+++ curl-7.19.7/lib/ftp.c
@@ -2798,12 +2798,6 @@ static CURLcode ftp_statemach_act(struct
             store++;
             ptr++;
           }
-          if(ftpc->entrypath)
-            free(ftpc->entrypath);
-          ftpc->entrypath =dir; /* remember this */
-          infof(data, "Entry path is '%s'\n", ftpc->entrypath);
-          /* also save it where getinfo can access it: */
-          data->state.most_recent_ftp_entrypath = ftpc->entrypath;
 
           /* If the path name does not look like an absolute path (i.e.: it
              does not start with a '/'), we probably need some server-dependent
@@ -2817,11 +2811,22 @@ static CURLcode ftp_statemach_act(struct
              if the path name looks strange to minimize overhead on other
              systems. */
 
-          if(!ftpc->server_os && ftpc->entrypath[0] != '/') {
+          if(!ftpc->server_os && dir[0] != '/') {
             NBFTPSENDF(conn, "SYST", NULL);
+            free(ftpc->entrypath);
+            ftpc->entrypath = dir; /* remember this */
+            infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+            /* also save it where getinfo can access it: */
+            data->state.most_recent_ftp_entrypath = ftpc->entrypath;
             state(conn, FTP_SYST);
             break;
           }
+
+          free(ftpc->entrypath);
+          ftpc->entrypath = dir; /* remember this */
+          infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+          /* also save it where getinfo can access it: */
+          data->state.most_recent_ftp_entrypath = ftpc->entrypath;
         }
         else {
           /* couldn't get the path */
Index: curl-7.19.7/tests/data/test1152
===================================================================
--- /dev/null
+++ curl-7.19.7/tests/data/test1152
@@ -0,0 +1,62 @@
+<testcase>
+<info>
+<keywords>
+FTP
+PASV
+LIST
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<servercmd>
+REPLY PWD 257 "just one
+</servercmd>
+
+# When doing LIST, we get the default list output hard-coded in the test
+# FTP server
+<data mode="text">
+total 20
+drwxr-xr-x   8 98       98           512 Oct 22 13:06 .
+drwxr-xr-x   8 98       98           512 Oct 22 13:06 ..
+drwxr-xr-x   2 98       98           512 May  2  1996 .NeXT
+-r--r--r--   1 0        1             35 Jul 16  1996 README
+lrwxrwxrwx   1 0        1              7 Dec  9  1999 bin -> usr/bin
+dr-xr-xr-x   2 0        1            512 Oct  1  1997 dev
+drwxrwxrwx   2 98       98           512 May 29 16:04 download.html
+dr-xr-xr-x   2 0        1            512 Nov 30  1995 etc
+drwxrwxrwx   2 98       1            512 Oct 30 14:33 pub
+dr-xr-xr-x   5 0        1            512 Oct  1  1997 usr
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+ftp
+</server>
+ <name>
+FTP with uneven quote in PWD response
+ </name>
+ <command>
+ftp://%HOSTIP:%FTPPORT/test-1152/
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+USER anonymous
+PASS ftp@example.com
+PWD
+SYST
+CWD test-1152
+EPSV
+TYPE A
+LIST
+QUIT
+</protocol>
+</verify>
+</testcase>
Index: curl-7.19.7/tests/data/Makefile.am
===================================================================
--- curl-7.19.7.orig/tests/data/Makefile.am
+++ curl-7.19.7/tests/data/Makefile.am
@@ -63,7 +63,8 @@ EXTRA_DIST = test1 test108 test117 test1
  test1089 test1090 test1091 test1092 test1093 test1094 test1095 test1096   \
  test1097 test560 test561 test1098 test1099 test562 test563 test1100       \
  test564 test1101 test1102 test1103 test1104 test299 test310 test311       \
- test312 test1105 test565 test1106 test1218 test1440 test1441 test1442
+ test312 test1105 test565 test1106 test1218 test1440 test1441 test1442     \
+ test1152
 
 filecheck:
 	@mkdir test-place; \
Index: curl-7.19.7/tests/data/Makefile.in
===================================================================
--- curl-7.19.7.orig/tests/data/Makefile.in
+++ curl-7.19.7/tests/data/Makefile.in
@@ -285,7 +285,8 @@ EXTRA_DIST = test1 test108 test117 test1
  test1089 test1090 test1091 test1092 test1093 test1094 test1095 test1096   \
  test1097 test560 test561 test1098 test1099 test562 test563 test1100       \
  test564 test1101 test1102 test1103 test1104 test299 test310 test311       \
- test312 test1105 test565 test1440 test1441 test1442
+ test312 test1105 test565 test1440 test1441 test1442                       \
+ test1152
 
 all: all-am
 
