diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am index ba48a511..c155444c 100644 --- a/fuzz/Makefile.am +++ b/fuzz/Makefile.am @@ -10,6 +10,7 @@ LDADD = ../lib/libgnu.a \ WGET_TESTS = \ wget_css_fuzzer$(EXEEXT) \ + wget_ftpls_fuzzer$(EXEEXT) \ wget_html_fuzzer$(EXEEXT) \ wget_options_fuzzer$(EXEEXT) @@ -34,6 +35,9 @@ endif wget_css_fuzzer_SOURCES = wget_css_fuzzer.c $(MAIN) wget_css_fuzzer_LDADD = ../src/libunittest.a $(LDADD) +wget_ftpls_fuzzer_SOURCES = wget_ftpls_fuzzer.c $(MAIN) +wget_ftpls_fuzzer_LDADD = ../src/libunittest.a $(LDADD) + wget_html_fuzzer_SOURCES = wget_html_fuzzer.c $(MAIN) wget_html_fuzzer_LDADD = ../src/libunittest.a $(LDADD) diff --git a/fuzz/wget_ftpls_fuzzer.c b/fuzz/wget_ftpls_fuzzer.c new file mode 100644 index 00000000..138a5492 --- /dev/null +++ b/fuzz/wget_ftpls_fuzzer.c @@ -0,0 +1,107 @@ +/* + * Copyright(c) 2017-2018 Free Software Foundation, Inc. + * + * This file is part of GNU Wget. + * + * GNU Wget is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GNU Wget is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Wget. If not, see . + */ + +#include + +#include +#include // opendir, readdir +#include // uint8_t +#include // fmemopen +#include // strncmp +#include // free +#include // open flags +#include // close +#include // longjmp, setjmp + +#include "wget.h" +#undef fopen_wgetrc + +#ifdef __cplusplus + extern "C" { +#endif + #include "ftp.h" + + // declarations for wget internal functions + int main_wget(int argc, const char **argv); + void cleanup(void); + FILE *fopen_wget(const char *pathname, const char *mode); + FILE *fopen_wgetrc(const char *pathname, const char *mode); + void exit_wget(int status); +#ifdef __cplusplus + } +#endif + +#include "fuzzer.h" + +FILE *fopen_wget(const char *pathname, const char *mode) +{ + return fopen("/dev/null", mode); +} + +FILE *fopen_wgetrc(const char *pathname, const char *mode) +{ + return NULL; +} + +#ifdef FUZZING +void exit_wget(int status) +{ +} +#else +void exit(int status) +{ +} +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + FILE *fp, *bak; + struct fileinfo *fi; + + if (size > 4096) // same as max_len = ... in .options file + return 0; + + bak = stderr; + stderr = fopen("/dev/null", "w"); + + fp = fmemopen((void *) data, size, "r"); + if (!fp) return 0; + + fi = ftp_parse_ls_fp(fp, ST_UNIX); + freefileinfo(fi); + rewind(fp); + + fi = ftp_parse_ls_fp(fp, ST_VMS); + freefileinfo(fi); + rewind(fp); + + fi = ftp_parse_ls_fp(fp, ST_WINNT); + freefileinfo(fi); + rewind(fp); + + fi = ftp_parse_ls_fp(fp, ST_MACOS); + freefileinfo(fi); + + fclose(fp); + + fclose(stderr); + stderr = bak; + + return 0; +} diff --git a/fuzz/wget_ftpls_fuzzer.dict b/fuzz/wget_ftpls_fuzzer.dict new file mode 100644 index 00000000..2137bfa8 --- /dev/null +++ b/fuzz/wget_ftpls_fuzzer.dict @@ -0,0 +1,20 @@ +"Jan" +"Feb" +"Mar" +"Apr" +"May" +"Jun" +"Jul" +"Aug" +"Sep" +"Oct" +"Nov" +"Dec" +"total" +"0644" +"0755" +" -> " +".." +"Total of " +".DIR" +".DIR;1" diff --git a/fuzz/wget_ftpls_fuzzer.in/starter b/fuzz/wget_ftpls_fuzzer.in/starter new file mode 100644 index 00000000..e9675bb9 --- /dev/null +++ b/fuzz/wget_ftpls_fuzzer.in/starter @@ -0,0 +1 @@ +-rwxr--r-- 1 owner group 640 1970 01 01 test diff --git a/src/ftp-ls.c b/src/ftp-ls.c index 4b33413a..6808eb6c 100644 --- a/src/ftp-ls.c +++ b/src/ftp-ls.c @@ -90,9 +90,8 @@ clean_line (char *line, int len) The time stamps are stored in a separate variable, time_t compatible (I hope). The timezones are ignored. */ static struct fileinfo * -ftp_parse_unix_ls (const char *file, int ignore_perms) +ftp_parse_unix_ls (FILE *fp, int ignore_perms) { - FILE *fp; static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" @@ -107,12 +106,6 @@ ftp_parse_unix_ls (const char *file, int ignore_perms) char *line = NULL, *tok, *ptok; /* tokenizer */ struct fileinfo *dir, *l, cur; /* list creation */ - fp = fopen (file, "rb"); - if (!fp) - { - logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); - return NULL; - } dir = l = NULL; /* Line loop to end of file: */ @@ -413,14 +406,12 @@ ftp_parse_unix_ls (const char *file, int ignore_perms) } xfree (line); - fclose (fp); return dir; } static struct fileinfo * -ftp_parse_winnt_ls (const char *file) +ftp_parse_winnt_ls (FILE *fp) { - FILE *fp; int len; int year, month, day; /* for time analysis */ int hour, min; @@ -431,12 +422,6 @@ ftp_parse_winnt_ls (const char *file) char *filename; struct fileinfo *dir, *l, cur; /* list creation */ - fp = fopen (file, "rb"); - if (!fp) - { - logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); - return NULL; - } dir = l = NULL; /* Line loop to end of file: */ @@ -562,7 +547,6 @@ ftp_parse_winnt_ls (const char *file) } xfree (line); - fclose(fp); return dir; } @@ -677,25 +661,18 @@ static void eat_carets( char *str) static struct fileinfo * -ftp_parse_vms_ls (const char *file) +ftp_parse_vms_ls (FILE *fp) { - FILE *fp; int dt, i, j, len; int perms; size_t bufsize = 0; time_t timenow; struct tm *timestruct; - char date_str[ 32]; + char date_str[32]; char *line = NULL, *tok; /* tokenizer */ struct fileinfo *dir, *l, cur; /* list creation */ - fp = fopen (file, "r"); - if (!fp) - { - logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); - return NULL; - } dir = l = NULL; /* Skip blank lines, Directory heading, and more blank lines. */ @@ -1003,7 +980,6 @@ ftp_parse_vms_ls (const char *file) } xfree (line); - fclose (fp); return dir; } @@ -1016,39 +992,51 @@ ftp_parse_vms_ls (const char *file) struct fileinfo * ftp_parse_ls (const char *file, const enum stype system_type) +{ + FILE *fp; + struct fileinfo *fi; + + fp = fopen (file, "rb"); + if (!fp) + { + logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); + return NULL; + } + + fi = ftp_parse_ls_fp (fp, system_type); + fclose(fp); + + return fi; +} + +struct fileinfo * +ftp_parse_ls_fp (FILE *fp, const enum stype system_type) { switch (system_type) { case ST_UNIX: - return ftp_parse_unix_ls (file, 0); + return ftp_parse_unix_ls (fp, 0); case ST_WINNT: { /* Detect whether the listing is simulating the UNIX format */ - FILE *fp; - int c; - fp = fopen (file, "rb"); - if (!fp) - { - logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); - return NULL; - } - c = fgetc(fp); - fclose(fp); + int c = fgetc(fp); + rewind(fp); + /* If the first character of the file is '0'-'9', it's WINNT format. */ if (c >= '0' && c <='9') - return ftp_parse_winnt_ls (file); + return ftp_parse_winnt_ls (fp); else - return ftp_parse_unix_ls (file, 1); + return ftp_parse_unix_ls (fp, 1); } case ST_VMS: - return ftp_parse_vms_ls (file); + return ftp_parse_vms_ls (fp); case ST_MACOS: - return ftp_parse_unix_ls (file, 1); + return ftp_parse_unix_ls (fp, 1); default: logprintf (LOG_NOTQUIET, _("\ Unsupported listing type, trying Unix listing parser.\n")); - return ftp_parse_unix_ls (file, 0); + return ftp_parse_unix_ls (fp, 0); } } diff --git a/src/ftp.c b/src/ftp.c index a0531df0..f11a9be0 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -2185,7 +2185,6 @@ static uerr_t ftp_retrieve_dirs (struct url *, struct url *, struct fileinfo *, ccon *); static uerr_t ftp_retrieve_glob (struct url *, struct url *, ccon *, int); static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **); -static void freefileinfo (struct fileinfo *f); /* Retrieve a list of files given in struct fileinfo linked list. If a file is a symbolic link, do not retrieve it, but rather try to @@ -2828,7 +2827,7 @@ delelement (struct fileinfo *f, struct fileinfo **start) } /* Free the fileinfo linked list of files. */ -static void +void freefileinfo (struct fileinfo *f) { while (f) diff --git a/src/ftp.h b/src/ftp.h index d30f8d0f..8f7c4c17 100644 --- a/src/ftp.h +++ b/src/ftp.h @@ -30,6 +30,9 @@ as that of the covered work. */ #ifndef FTP_H #define FTP_H +#include +#include + #include "host.h" #include "url.h" @@ -167,6 +170,8 @@ enum wget_ftp_fstatus }; struct fileinfo *ftp_parse_ls (const char *, const enum stype); +struct fileinfo *ftp_parse_ls_fp (FILE *, const enum stype); +void freefileinfo(struct fileinfo *); uerr_t ftp_loop (struct url *, struct url *, char **, int *, struct url *, bool, bool);