Add new fuzzer for the FTP listing parsers

* fuzz/Makefile.am: Add wget_ftpls_fuzzer
* fuzz/wget_ftpls_fuzzer.c: New fuzzer
* fuzz/wget_ftpls_fuzzer.dict: Fuzzer dictionary
* fuzz/wget_ftpls_fuzzer.in/starter: Starting corpus
* src/ftp-ls.c: Parsing function take FILE * as argument,
  new function ftp_parse_ls_fp()
* src/ftp.c: Remove static from freefileinfo()
* src/ftp.h: Add ftp_parse_ls_fp() and freefileinfo()
This commit is contained in:
Tim Rühsen 2018-04-21 19:24:18 +02:00
parent fbc5f3736e
commit 407cd5f23b
7 changed files with 170 additions and 46 deletions

View File

@ -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)

107
fuzz/wget_ftpls_fuzzer.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <sys/types.h>
#include <dirent.h> // opendir, readdir
#include <stdint.h> // uint8_t
#include <stdio.h> // fmemopen
#include <string.h> // strncmp
#include <stdlib.h> // free
#include <fcntl.h> // open flags
#include <unistd.h> // close
#include <setjmp.h> // 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;
}

View File

@ -0,0 +1,20 @@
"Jan"
"Feb"
"Mar"
"Apr"
"May"
"Jun"
"Jul"
"Aug"
"Sep"
"Oct"
"Nov"
"Dec"
"total"
"0644"
"0755"
" -> "
".."
"Total of "
".DIR"
".DIR;1"

View File

@ -0,0 +1 @@
-rwxr--r-- 1 owner group 640 1970 01 01 test

View File

@ -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);
}
}

View File

@ -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)

View File

@ -30,6 +30,9 @@ as that of the covered work. */
#ifndef FTP_H
#define FTP_H
#include <stdio.h>
#include <stdbool.h>
#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);