Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ftplistparser: free off temporary memory always #2013

Closed
wants to merge 1 commit into from
Closed

ftplistparser: free off temporary memory always #2013

wants to merge 1 commit into from

Conversation

cmeister2
Copy link
Contributor

When using the FTP list parser, ensure that the memory that's
allocated is always freed.

Detected by OSS-fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3682


I haven't been able to test this using the standard test suite, but the fuzzer no longer complains about leaking memory after applying this patch.

When using the FTP list parser, ensure that the memory that's
allocated is always freed.

Detected by OSS-fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3682
@bagder
Copy link
Member

bagder commented Oct 25, 2017

Lovely. Thanks a lot!

I would prefer to have the label in lowercase like wo do elsewhere, and while there I think we should cleanup the PL_ERROR function that with your fix isn't necessary anymore. So I propose the following follow-up/amend. Thoughts?

From a8ea21e4f67e2d6065ed3ea276e9e843212017a2 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Wed, 25 Oct 2017 18:19:44 +0200
Subject: [PATCH] ftplistparser: follow-up cleanup to remove PL_ERROR()

---
 lib/ftplistparser.c | 167 ++++++++++++++++++++++++----------------------------
 1 file changed, 78 insertions(+), 89 deletions(-)

diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c
index 58a49722b..262ac0306 100644
--- a/lib/ftplistparser.c
+++ b/lib/ftplistparser.c
@@ -262,20 +262,10 @@ static int ftp_pl_get_permission(const char *str)
     permissions |= FTP_LP_MALFORMATED_PERM;
 
   return permissions;
 }
 
-static void PL_ERROR(struct connectdata *conn, CURLcode err)
-{
-  struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
-  struct ftp_parselist_data *parser = tmpdata->parser;
-  if(parser->file_data)
-    Curl_fileinfo_dtor(NULL, parser->file_data);
-  parser->file_data = NULL;
-  parser->error = err;
-}
-
 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
                                     struct fileinfo *infop)
 {
   curl_fnmatch_callback compare;
   struct WildcardData *wc = &conn->data->wildcard;
@@ -345,11 +335,11 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
      * 1. call => OK..
      * 2. call => OUT_OF_MEMORY (or other error)
      * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
      *    in wc_statemach()
      */
-    goto EXIT_LABEL;
+    goto fail;
   }
 
   if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
     /* considering info about FILE response format */
     parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
@@ -361,16 +351,16 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
     char c = buffer[i];
     if(!parser->file_data) { /* tmp file data is not allocated yet */
       parser->file_data = Curl_fileinfo_alloc();
       if(!parser->file_data) {
         parser->error = CURLE_OUT_OF_MEMORY;
-        goto EXIT_LABEL;
+        goto fail;
       }
       parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
       if(!parser->file_data->info.b_data) {
-        PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
-        goto EXIT_LABEL;
+        parser->error = CURLE_OUT_OF_MEMORY;
+        goto fail;
       }
       parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
       parser->item_offset = 0;
       parser->item_length = 0;
     }
@@ -389,12 +379,11 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
       }
       else {
         Curl_fileinfo_dtor(NULL, parser->file_data);
         parser->file_data = NULL;
         parser->error = CURLE_OUT_OF_MEMORY;
-        PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
-        goto EXIT_LABEL;
+        goto fail;
       }
     }
 
     switch(parser->os_type) {
     case OS_TYPE_UNIX:
@@ -428,19 +417,19 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
               while(ISSPACE(*endptr))
                 endptr++;
               while(ISDIGIT(*endptr))
                 endptr++;
               if(*endptr != 0) {
-                PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-                goto EXIT_LABEL;
+                parser->error = CURLE_FTP_BAD_FILE_LIST;
+                goto fail;
               }
               parser->state.UNIX.main = PL_UNIX_FILETYPE;
               finfo->b_used = 0;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              goto EXIT_LABEL;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
         }
         break;
@@ -469,36 +458,36 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           break;
         case 'D':
           finfo->filetype = CURLFILETYPE_DOOR;
           break;
         default:
-          PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-          goto EXIT_LABEL;
+          parser->error = CURLE_FTP_BAD_FILE_LIST;
+          goto fail;
         }
         parser->state.UNIX.main = PL_UNIX_PERMISSION;
         parser->item_length = 0;
         parser->item_offset = 1;
         break;
       case PL_UNIX_PERMISSION:
         parser->item_length++;
         if(parser->item_length <= 9) {
           if(!strchr("rwx-tTsS", c)) {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
         }
         else if(parser->item_length == 10) {
           unsigned int perm;
           if(c != ' ') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           finfo->b_data[10] = 0; /* terminate permissions */
           perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
           if(perm & FTP_LP_MALFORMATED_PERM) {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
           parser->file_data->info.perm = perm;
           parser->offsets.perm = parser->item_offset;
 
@@ -515,12 +504,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
               parser->item_offset = finfo->b_used - 1;
               parser->item_length = 1;
               parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              goto EXIT_LABEL;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
         case PL_UNIX_HLINKS_NUMBER:
           parser->item_length ++;
@@ -537,12 +526,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             parser->item_offset = 0;
             parser->state.UNIX.main = PL_UNIX_USER;
             parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
           }
           else if(c < '0' || c > '9') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
         break;
       case PL_UNIX_USER:
@@ -597,12 +586,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
               parser->item_offset = finfo->b_used - 1;
               parser->item_length = 1;
               parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              goto EXIT_LABEL;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
         case PL_UNIX_SIZE_NUMBER:
           parser->item_length++;
@@ -622,12 +611,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
               parser->state.UNIX.main = PL_UNIX_TIME;
               parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
             }
           }
           else if(!ISDIGIT(c)) {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
         break;
       case PL_UNIX_TIME:
@@ -638,56 +627,56 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
               parser->item_offset = finfo->b_used -1;
               parser->item_length = 1;
               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              goto EXIT_LABEL;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
         case PL_UNIX_TIME_PART1:
           parser->item_length++;
           if(c == ' ') {
             parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
           }
           else if(!ISALNUM(c) && c != '.') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         case PL_UNIX_TIME_PREPART2:
           parser->item_length++;
           if(c != ' ') {
             if(ISALNUM(c)) {
               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              goto EXIT_LABEL;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
         case PL_UNIX_TIME_PART2:
           parser->item_length++;
           if(c == ' ') {
             parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
           }
           else if(!ISALNUM(c) && c != '.') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         case PL_UNIX_TIME_PREPART3:
           parser->item_length++;
           if(c != ' ') {
             if(ISALNUM(c)) {
               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              goto EXIT_LABEL;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
         case PL_UNIX_TIME_PART3:
           parser->item_length++;
@@ -707,12 +696,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
               parser->state.UNIX.main = PL_UNIX_FILENAME;
               parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
             }
           }
           else if(!ISALNUM(c) && c != '.' && c != ':') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
         break;
       case PL_UNIX_FILENAME:
@@ -733,29 +722,29 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              goto EXIT_LABEL;
+              parser->error = result;
+              goto fail;
             }
           }
           break;
         case PL_UNIX_FILENAME_WINDOWSEOL:
           if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              goto EXIT_LABEL;
+              parser->error = result;
+              goto fail;
             }
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
         break;
       case PL_UNIX_SYMLINK:
@@ -771,22 +760,22 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           parser->item_length++;
           if(c == ' ') {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
           }
           else if(c == '\r' || c == '\n') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         case PL_UNIX_SYMLINK_PRETARGET1:
           parser->item_length++;
           if(c == '-') {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
           }
           else if(c == '\r' || c == '\n') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           else {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
           }
           break;
@@ -794,12 +783,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           parser->item_length++;
           if(c == '>') {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
           }
           else if(c == '\r' || c == '\n') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           else {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
           }
           break;
@@ -812,12 +801,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             parser->offsets.filename = parser->item_offset;
             parser->item_length = 0;
             parser->item_offset = 0;
           }
           else if(c == '\r' || c == '\n') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           else {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
           }
           break;
@@ -826,12 +815,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
             parser->item_offset = finfo->b_used - 1;
             parser->item_length = 1;
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         case PL_UNIX_SYMLINK_TARGET:
           parser->item_length++;
           if(c == '\r') {
@@ -840,30 +829,30 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           else if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.symlink_target = parser->item_offset;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              goto EXIT_LABEL;
+              parser->error = result;
+              goto fail;
             }
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
           }
           break;
         case PL_UNIX_SYMLINK_WINDOWSEOL:
           if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.symlink_target = parser->item_offset;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              goto EXIT_LABEL;
+              parser->error = result;
+              goto fail;
             }
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
         break;
       }
@@ -872,27 +861,27 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
       switch(parser->state.NT.main) {
       case PL_WINNT_DATE:
         parser->item_length++;
         if(parser->item_length < 9) {
           if(!strchr("0123456789-", c)) { /* only simple control */
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
         }
         else if(parser->item_length == 9) {
           if(c == ' ') {
             parser->state.NT.main = PL_WINNT_TIME;
             parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
         }
         else {
-          PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-          goto EXIT_LABEL;
+          parser->error = CURLE_FTP_BAD_FILE_LIST;
+          goto fail;
         }
         break;
       case PL_WINNT_TIME:
         parser->item_length++;
         switch(parser->state.NT.sub.time) {
@@ -908,12 +897,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             parser->state.NT.main = PL_WINNT_DIRORSIZE;
             parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
             parser->item_length = 0;
           }
           else if(!strchr("APM0123456789:", c)) {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
         break;
       case PL_WINNT_DIRORSIZE:
@@ -939,12 +928,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             else {
               char *endptr;
               if(curlx_strtoofft(finfo->b_data +
                                  parser->item_offset,
                                  &endptr, 10, &finfo->size)) {
-                PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-                goto EXIT_LABEL;
+                parser->error = CURLE_FTP_BAD_FILE_LIST;
+                goto fail;
               }
               /* correct file type */
               parser->file_data->info.filetype = CURLFILETYPE_FILE;
             }
 
@@ -975,49 +964,49 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             parser->offsets.filename = parser->item_offset;
             finfo->b_data[finfo->b_used - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              goto EXIT_LABEL;
+              parser->error = result;
+              goto fail;
             }
             parser->state.NT.main = PL_WINNT_DATE;
             parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
           }
           break;
         case PL_WINNT_FILENAME_WINEOL:
           if(c == '\n') {
             parser->offsets.filename = parser->item_offset;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              goto EXIT_LABEL;
+              parser->error = result;
+              goto fail;
             }
             parser->state.NT.main = PL_WINNT_DATE;
             parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            goto EXIT_LABEL;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
         break;
       }
       break;
     default:
       retsize = bufflen + 1;
-      goto EXIT_LABEL;
+      goto fail;
     }
 
     i++;
   }
 
-EXIT_LABEL:
+fail:
 
   /* Clean up any allocated memory. */
-  if(parser->file_data != NULL) {
+  if(parser->file_data) {
     Curl_fileinfo_dtor(NULL, parser->file_data);
     parser->file_data = NULL;
   }
 
   return retsize;
-- 
2.14.1

@cmeister2
Copy link
Contributor Author

Looks great. Do you want me to patch it on top of mine, or do you want to handle that as part of merging in?

@bagder
Copy link
Member

bagder commented Oct 25, 2017

I just wanted to run it by you first, I'll just add that commit when I merge.

@bagder bagder closed this in f786d1f Oct 25, 2017
@bagder
Copy link
Member

bagder commented Oct 25, 2017

Thanks!

@lock lock bot locked as resolved and limited conversation to collaborators Jan 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants