current fuzz.c, NONE, 1.1 GNUmakefile.in, 1.252, 1.253 actions.c, 1.97, 1.98 actions.h, 1.24, 1.25 configure.in, 1.206, 1.207 errlog.c, 1.126, 1.127 errlog.h, 1.30, 1.31 filters.c, 1.202, 1.203 filters.h, 1.47, 1.48 gateway.c, 1.99, 1.100 gateway.h, 1.23, 1.24 jbsockets.c, 1.138, 1.139 jcc.c, 1.448, 1.449 jcc.h, 1.36, 1.37 loaders.c, 1.105, 1.106 loaders.h, 1.32, 1.33 parsers.c, 1.310, 1.311 pcrs.c, 1.50, 1.51 pcrs.h, 1.18, 1.19 project.h, 1.217, 1.218 urlmatch.c, 1.88, 1.89
Fabian Keil <[email protected]> Sat, 24 Dec 2016 16:00:51 +0000
| Newsgroups | gmane.comp.web.privoxy.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/ijbswa/current In directory sfp-cvs-1.v30.ch3.sourceforge.com:/tmp/cvs-serv25104 Modified Files: GNUmakefile.in actions.c actions.h configure.in errlog.c errlog.h filters.c filters.h gateway.c gateway.h jbsockets.c jcc.c jcc.h loaders.c loaders.h parsers.c pcrs.c pcrs.h project.h urlmatch.c Added Files: fuzz.c Log Message: Add a --fuzz option ... which exposes Privoxy internals to input from files or stdout. Mainly tested with American Fuzzy Lop. For details see: https://www.fabiankeil.de/talks/fuzzing-on-freebsd/ This work was partially funded with donations and done as part of the Privoxy month in 2015. Hohoho. Index: project.h =================================================================== RCS file: /cvsroot/ijbswa/current/project.h,v retrieving revision 1.217 retrieving revision 1.218 diff -C2 -d -r1.217 -r1.218 *** project.h 27 Sep 2016 22:48:28 -0000 1.217 --- project.h 24 Dec 2016 16:00:49 -0000 1.218 *************** *** 862,865 **** --- 862,871 ---- #define CSP_FLAG_CRUNCHED 0x04000000U + #ifdef FUZZ + /** + * Flag for csp->flags: Set if we are working with fuzzed input + */ + #define CSP_FLAG_FUZZED_INPUT 0x08000000U + #endif /* Index: gateway.h =================================================================== RCS file: /cvsroot/ijbswa/current/gateway.h,v retrieving revision 1.23 retrieving revision 1.24 diff -C2 -d -r1.23 -r1.24 *** gateway.h 24 Nov 2013 14:23:28 -0000 1.23 --- gateway.h 24 Dec 2016 16:00:49 -0000 1.24 *************** *** 67,70 **** --- 67,74 ---- #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + #ifdef FUZZ + extern jb_err socks_fuzz(struct client_state *csp); + #endif + /* * Revision control strings from this header and associated .c file Index: loaders.h =================================================================== RCS file: /cvsroot/ijbswa/current/loaders.h,v retrieving revision 1.32 retrieving revision 1.33 diff -C2 -d -r1.32 -r1.33 *** loaders.h 24 Nov 2013 14:23:28 -0000 1.32 --- loaders.h 24 Dec 2016 16:00:49 -0000 1.33 *************** *** 75,78 **** --- 75,81 ---- extern int load_action_files(struct client_state *csp); extern int load_re_filterfiles(struct client_state *csp); + #ifdef FUZZ + extern int load_one_re_filterfile(struct client_state *csp, int fileid); + #endif #ifdef FEATURE_TRUST --- NEW FILE: fuzz.c --- /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/fuzz.c,v $ * * Purpose : Fuzz-related functions for Privoxy. * * Copyright : Written by and Copyright (C) 2014-16 by * Fabian Keil <[email protected]> * * This program 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 2 of the License, or (at * your option) any later version. * * This program 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. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include "project.h" #include "filters.h" #include "loaders.h" #include "parsers.h" #include "miscutil.h" #include "errlog.h" #include "actions.h" #include "cgi.h" #include "loadcfg.h" #include "urlmatch.h" #include "filters.h" #include "jbsockets.h" #include "gateway.h" #include "jcc.h" #include "list.h" #ifdef FUZZ static int fuzz_action(struct client_state *csp, char *fuzz_input_file); static int fuzz_client_header(struct client_state *csp, char *fuzz_input_file); static int fuzz_deflate(struct client_state *csp, char *fuzz_input_file); static int fuzz_filter(struct client_state *csp, char *fuzz_input_file); static int fuzz_gif(struct client_state *csp, char *fuzz_input_file); static int fuzz_gzip(struct client_state *csp, char *fuzz_input_file); #ifdef FUZZ_SOCKS static int fuzz_socks(struct client_state *csp, char *fuzz_input_file); #endif static int fuzz_pcrs_substitute(struct client_state *csp, char *fuzz_input_file); static int fuzz_server_header(struct client_state *csp, char *fuzz_input_file); struct fuzz_mode { const char *name; const char *expected_input; const int stdin_support; int (* const handler)(struct client_state *csp, char *input_file); }; static const struct fuzz_mode fuzz_modes[] = { { "action", "Text to parse as action file.", 0, fuzz_action }, { "client-request", "Client request to parse. Currently incomplete", 1, fuzz_client_request }, { "client-header", "Client header to parse.", 1, fuzz_client_header }, { "chunked-transfer-encoding", "Chunk-encoded data to dechunk.", 1, fuzz_chunked_transfer_encoding }, { "deflate", "deflate-compressed data to decompress.", 1, fuzz_deflate }, { "filter", "Text to parse as filter file.", 0, fuzz_filter }, { "gif", "gif to deanimate.", 1, fuzz_gif }, { "gzip", "gzip-compressed data to decompress.", 1, fuzz_gzip }, { "pcrs-substitute", "A pcrs-substitute to compile. Not a whole pcrs job! Example: Bla $1 bla \x43 $3 blah.", 1, fuzz_pcrs_substitute }, { "server-header", "Server header to parse.", 1, fuzz_server_header }, { "server-response", "Server response to parse.", 1, fuzz_server_response }, #ifdef FUZZ_SOCKS { "socks", "A socks server response. Only reads from stdin!", 1, fuzz_socks }, #endif }; /********************************************************************* * * Function : load_fuzz_input_from_stdin * * Description : Loads stdin into a buffer. * * Parameters : * 1 : csp = Used to store the data. * * Returns : JB_ERR_OK in case of success, * *********************************************************************/ static jb_err load_fuzz_input_from_stdin(struct client_state *csp) { static char buf[BUFFER_SIZE]; int ret; while (0 < (ret = read_socket(0, buf, sizeof(buf)))) { log_error(LOG_LEVEL_INFO, "Got %d bytes from stdin: %E. They look like this: %N", ret, ret, buf); if (add_to_iob(csp->iob, csp->config->buffer_limit, buf, ret)) { log_error(LOG_LEVEL_FATAL, "Failed to buffer them."); } } log_error(LOG_LEVEL_INFO, "Read %d bytes from stdin", csp->iob->eod -csp->iob->cur); return JB_ERR_OK; } /********************************************************************* * * Function : load_fuzz_input_from_file * * Description : Loads file content into a buffer. * * Parameters : * 1 : csp = Used to store the data. * 2 : filename = Name of the file to be loaded. * * Returns : JB_ERR_OK in case of success, * *********************************************************************/ static jb_err load_fuzz_input_from_file(struct client_state *csp, const char *filename) { FILE *fp; size_t length; long ret; fp = fopen(filename, "rb"); if (NULL == fp) { log_error(LOG_LEVEL_FATAL, "Failed to open %s: %E", filename); } /* Get file length */ if (fseek(fp, 0, SEEK_END)) { log_error(LOG_LEVEL_FATAL, "Unexpected error while fseek()ing to the end of %s: %E", filename); } ret = ftell(fp); if (-1 == ret) { log_error(LOG_LEVEL_FATAL, "Unexpected ftell() error while loading %s: %E", filename); } length = (size_t)ret; /* Go back to the beginning. */ if (fseek(fp, 0, SEEK_SET)) { log_error(LOG_LEVEL_FATAL, "Unexpected error while fseek()ing to the beginning of %s: %E", filename); } csp->iob->size = length + 1; csp->iob->buf = malloc_or_die(csp->iob->size); csp->iob->cur = csp->iob->buf; csp->iob->eod = csp->iob->buf + length; if (1 != fread(csp->iob->cur, length, 1, fp)) { /* * May theoretically happen if the file size changes between * fseek() and fread() because it's edited in-place. Privoxy * and common text editors don't do that, thus we just fail. */ log_error(LOG_LEVEL_FATAL, "Couldn't completely read file %s.", filename); } *csp->iob->eod = '\0'; fclose(fp); return JB_ERR_OK; } /********************************************************************* * * Function : load_fuzz_input * * Description : Loads a file into a buffer. XXX: Reverse argument order * * Parameters : * 1 : csp = Used to store the data. * 2 : filename = Name of the file to be loaded. * * Returns : JB_ERR_OK in case of success, * *********************************************************************/ jb_err load_fuzz_input(struct client_state *csp, const char *filename) { if (strcmp(filename, "-") == 0) { return load_fuzz_input_from_stdin(csp); } return load_fuzz_input_from_file(csp, filename); } /********************************************************************* * * Function : remove_forbidden_bytes * * Description : Sanitizes fuzzed data to decrease the likelihood of * premature parse abortions. * * Parameters : * 1 : csp = Used to store the data. * * Returns : N/A * *********************************************************************/ static void remove_forbidden_bytes(struct client_state *csp) { char *p = csp->iob->cur; char first_valid_byte = ' '; while (p < csp->iob->eod) { if (*p != '\0') { first_valid_byte = *p; break; } p++; } p = csp->iob->cur; while (p < csp->iob->eod) { if (*p == '\0') { *p = first_valid_byte; } p++; } } /********************************************************************* * * Function : fuzz_action * * Description : Treat the fuzzed input as action file. * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ int fuzz_action(struct client_state *csp, char *fuzz_input_file) { csp->config->actions_file[0] = fuzz_input_file; return(load_action_files(csp)); } /********************************************************************* * * Function : fuzz_client_header * * Description : Treat the fuzzed input as a client header. * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ int fuzz_client_header(struct client_state *csp, char *fuzz_input_file) { char *header; header = get_header(csp->iob); if (NULL == header) { return 1; } if (JB_ERR_OK != enlist(csp->headers, header)) { return 1; } /* * Silence an insightful client_host_adder() warning * about ignored weirdness. */ csp->flags |= CSP_FLAG_HOST_HEADER_IS_SET; /* Adding headers doesn't depend on the fuzzed input */ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET; /* +hide-if-modified-since{+60} */ csp->action->flags |= ACTION_HIDE_IF_MODIFIED_SINCE; csp->action->string[ACTION_STRING_IF_MODIFIED_SINCE] = "+60"; /* XXX: Enable more actions. */ return(sed(csp, FILTER_CLIENT_HEADERS)); } /********************************************************************* * * Function : fuzz_filter * * Description : Treat the fuzzed input as filter file. * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ int fuzz_filter(struct client_state *csp, char *fuzz_input_file) { csp->config->re_filterfile[0] = fuzz_input_file; return (load_one_re_filterfile(csp, 0)); } /********************************************************************* * * Function : fuzz_deflate * * Description : Treat the fuzzed input as data to deflate. * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ static int fuzz_deflate(struct client_state *csp, char *fuzz_input_file) { csp->content_type = CT_DEFLATE; return(JB_ERR_OK == decompress_iob(csp)); } /********************************************************************* * * Function : fuzz_gif * * Description : Treat the fuzzed input as a gif to deanimate. * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ static int fuzz_gif(struct client_state *csp, char *fuzz_input_file) { char *deanimated_gif; if (6 < csp->iob->size) { /* Why yes of course, officer, this is a gif. */ memcpy(csp->iob->cur, "GIF87a", 6); } /* Using the last image requires parsing of all images */ csp->action->string[ACTION_STRING_DEANIMATE] = "last"; deanimated_gif = gif_deanimate_response(csp); if (NULL != deanimated_gif) { free(deanimated_gif); return 0; } return 1; } /********************************************************************* * * Function : fuzz_gzip * * Description : Treat the fuzzed input as data to unzip * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ static int fuzz_gzip(struct client_state *csp, char *fuzz_input_file) { csp->content_type = CT_GZIP; return(JB_ERR_OK == decompress_iob(csp)); } #ifdef FUZZ_SOCKS /********************************************************************* * * Function : fuzz_socks * * Description : Treat the fuzzed input as a socks response. * XXX: This is pretty useless as parsing socks repsonse * is trivial. * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ static int fuzz_socks(struct client_state *csp, char *fuzz_input_file) { return(JB_ERR_OK == socks_fuzz(csp)); } #endif /********************************************************************* * * Function : fuzz_pcrs_substitute * * Description : Treat the fuzzed input as a pcrs substitute. * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ static int fuzz_pcrs_substitute(struct client_state *csp, char *fuzz_input_file) { static pcrs_substitute *result; int err; remove_forbidden_bytes(csp); result = pcrs_compile_fuzzed_replacement(csp->iob->cur, &err); if (NULL == result) { log_error(LOG_LEVEL_ERROR, "Failed to compile pcrs replacement. Error: %s", pcrs_strerror(err)); return 1; } log_error(LOG_LEVEL_INFO, "%s", pcrs_strerror(err)); free(result->text); freez(result); return 0; } /********************************************************************* * * Function : fuzz_server_header * * Description : Treat the fuzzed input as a server header. * * Parameters : * 1 : csp = Used to store the data. * 2 : fuzz_input_file = File to read the input from. * * Returns : Result of fuzzed function * *********************************************************************/ int fuzz_server_header(struct client_state *csp, char *fuzz_input_file) { char *header; header = get_header(csp->iob); if (NULL == header) { return 1; } if (JB_ERR_OK != enlist(csp->headers, header)) { return 1; } /* Adding headers doesn't depend on the fuzzed input */ csp->flags |= CSP_FLAG_CLIENT_HEADER_PARSING_DONE; csp->flags |= CSP_FLAG_SERVER_CONNECTION_HEADER_SET; /* +overwrite-last-modified{randomize} */ csp->action->flags |= ACTION_OVERWRITE_LAST_MODIFIED; csp->action->string[ACTION_STRING_LAST_MODIFIED] = "randomize"; /* +limit-cookie-lifetime{60} */ csp->action->flags |= ACTION_LIMIT_COOKIE_LIFETIME; csp->action->string[ACTION_STRING_LIMIT_COOKIE_LIFETIME] = "60"; /* XXX: Enable more actions. */ return(sed(csp, FILTER_SERVER_HEADERS)); } /********************************************************************* * * Function : process_fuzzed_input * * Description : Process the fuzzed input in a specified file treating * it like the input type specified. * * XXX: Does not check malloc succcess. * * Parameters : * 1 : fuzz_input_type = Type of input. * 2 : fuzz_input_file = File to read the input from. * * Returns : Return value of the fuzzed function * *********************************************************************/ int process_fuzzed_input(char *fuzz_input_type, char *fuzz_input_file) { static struct client_state csp_stack_storage; static struct configuration_spec config_stack_storage; struct client_state *csp; int i; csp = &csp_stack_storage; csp->config = &config_stack_storage; csp->config->buffer_limit = 4096 * 1024; /* In --stfu mode, these will be ignored ... */ set_debug_level(LOG_LEVEL_ACTIONS|LOG_LEVEL_CONNECT|LOG_LEVEL_DEANIMATE|LOG_LEVEL_INFO|LOG_LEVEL_ERROR|LOG_LEVEL_RE_FILTER|LOG_LEVEL_HEADER|LOG_LEVEL_WRITING|LOG_LEVEL_RECEIVED); csp->flags |= CSP_FLAG_FUZZED_INPUT; csp->config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS; #ifdef FEATURE_CLIENT_TAGS csp->config->trust_x_forwarded_for = 1; #endif for (i = 0; i < SZ(fuzz_modes); i++) { if (strcmp(fuzz_modes[i].name, fuzz_input_type) == 0) { if (fuzz_modes[i].stdin_support && (strcmp(fuzz_input_type, "client-request") != 0) && (strcmp(fuzz_input_type, "server-response") != 0) && (strcmp(fuzz_input_type, "socks") != 0)) { load_fuzz_input(csp, fuzz_input_file); } return (fuzz_modes[i].handler(csp, fuzz_input_file)); } } log_error(LOG_LEVEL_FATAL, "Unrecognized fuzz type %s for input file %s. You may need --help.", fuzz_input_type, fuzz_input_file); /* Not reached. */ return 1; } /********************************************************************* * * Function : show_fuzz_usage * * Description : Shows the --fuzz usage. D'oh. * * Parameters : Pointer to argv[0] for identifying ourselves * * Returns : void * *********************************************************************/ void show_fuzz_usage(const char *name) { int i; printf("%s%s --fuzz fuzz-mode ./path/to/fuzzed/input [--stfu]\n\n", " ", name); printf("Supported fuzz modes and the expected input:\n"); for (i = 0; i < SZ(fuzz_modes); i++) { printf(" %s: %s\n", fuzz_modes[i].name, fuzz_modes[i].expected_input); } printf("\n"); printf("The following fuzz modes read data from stdin if the 'file' is '-'\n"); for (i = 0; i < SZ(fuzz_modes); i++) { if (fuzz_modes[i].stdin_support) { printf(" %s\n", fuzz_modes[i].name); } } printf("\n"); } #endif Index: pcrs.h =================================================================== RCS file: /cvsroot/ijbswa/current/pcrs.h,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** pcrs.h 24 Nov 2013 14:23:28 -0000 1.18 --- pcrs.h 24 Dec 2016 16:00:49 -0000 1.19 *************** *** 134,137 **** --- 134,141 ---- #endif /* ndef PCRS_BUFFER_SIZE */ + #ifdef FUZZ + extern pcrs_substitute *pcrs_compile_fuzzed_replacement(const char *replacement, int *errptr); + #endif + #endif /* ndef PCRS_H_INCLUDED */ Index: configure.in =================================================================== RCS file: /cvsroot/ijbswa/current/configure.in,v retrieving revision 1.206 retrieving revision 1.207 diff -C2 -d -r1.206 -r1.207 *** configure.in 27 Sep 2016 22:48:28 -0000 1.206 --- configure.in 24 Dec 2016 16:00:49 -0000 1.207 *************** *** 1028,1031 **** --- 1028,1041 ---- AC_SUBST(FEATURE_CLIENT_TAGS_ONLY) + AC_ARG_ENABLE(fuzz, + [ --enable-fuzz Enable code that makes fuzzing more convenient], + [if test $enableval = yes; then + FUZZ_ONLY="" + AC_DEFINE(FUZZ,1,[Define to make fuzzing more convenient.]) + else + FUZZ_ONLY="#" + fi]) + AC_SUBST(FUZZ_ONLY) + dnl pcre/pcrs is needed for CGI anyway, so dnl the choice is only between static and Index: loaders.c =================================================================== RCS file: /cvsroot/ijbswa/current/loaders.c,v retrieving revision 1.105 retrieving revision 1.106 diff -C2 -d -r1.105 -r1.106 *** loaders.c 25 May 2016 10:50:55 -0000 1.105 --- loaders.c 24 Dec 2016 16:00:49 -0000 1.106 *************** *** 75,79 **** --- 75,81 ---- #endif /* def FEATURE_TRUST */ + #ifndef FUZZ static int load_one_re_filterfile(struct client_state *csp, int fileid); + #endif static struct file_list *current_re_filterfile[MAX_AF_FILES] = { *************** *** 362,365 **** --- 364,368 ---- { ch = getc(fp); + if (ch == EOF) { *************** *** 418,421 **** --- 421,425 ---- else if (ch == 0) { + /* XXX: Why do we allow this anyway? */ *p = '\0'; *dest = buf; Index: GNUmakefile.in =================================================================== RCS file: /cvsroot/ijbswa/current/GNUmakefile.in,v retrieving revision 1.252 retrieving revision 1.253 diff -C2 -d -r1.252 -r1.253 *** GNUmakefile.in 28 Jul 2016 08:16:04 -0000 1.252 --- GNUmakefile.in 24 Dec 2016 16:00:49 -0000 1.253 *************** *** 198,201 **** --- 198,204 ---- CLIENT_TAG_OBJS = @FEATURE_CLIENT_TAGS_ONLY@client-tags.@OBJEXT@ + FUZZ_SRC = @[email protected] + FUZZ_OBJS = @FUZZ_ONLY@fuzz.@OBJEXT@ + W32_SRC = @[email protected] w32taskbar.c win32.c w32svrapi.c W32_FILES = @[email protected] *************** *** 229,234 **** PTHREAD_LIB = @PTHREAD_ONLY@@PTHREAD_LIB@ ! SRCS = $(C_SRC) $(CLIENT_TAG_SRC) $(W32_SRC) $(PCRS_SRC) $(PCRE_SRC) $(REGEX_SRC) ! OBJS = $(C_OBJS) $(CLIENT_TAG_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(PCRE_OBJS) $(REGEX_OBJS) HDRS = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(PCRE_OBJS) $(REGEX_HDRS) LIBS = @LIBS@ $(W32_LIB) $(SOCKET_LIB) $(PTHREAD_LIB) --- 232,237 ---- PTHREAD_LIB = @PTHREAD_ONLY@@PTHREAD_LIB@ ! SRCS = $(C_SRC) $(CLIENT_TAG_SRC) $(FUZZ_SRC) $(W32_SRC) $(PCRS_SRC) $(PCRE_SRC) $(REGEX_SRC) ! OBJS = $(C_OBJS) $(CLIENT_TAG_OBJS) $(FUZZ_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(PCRE_OBJS) $(REGEX_OBJS) HDRS = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(PCRE_OBJS) $(REGEX_HDRS) LIBS = @LIBS@ $(W32_LIB) $(SOCKET_LIB) $(PTHREAD_LIB) Index: gateway.c =================================================================== RCS file: /cvsroot/ijbswa/current/gateway.c,v retrieving revision 1.99 retrieving revision 1.100 diff -C2 -d -r1.99 -r1.100 *** gateway.c 25 Oct 2016 10:46:56 -0000 1.99 --- gateway.c 24 Dec 2016 16:00:49 -0000 1.100 *************** *** 665,668 **** --- 665,713 ---- + #ifdef FUZZ_SOCKS + /********************************************************************* + * + * Function : socks_fuzz + * + * Description : Wrapper around socks[45]_connect() used for fuzzing. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : JB_ERR_OK or JB_ERR_PARSE + * + *********************************************************************/ + extern jb_err socks_fuzz(struct client_state *csp) + { + jb_socket socket; + static struct forward_spec fwd; + char target_host[] = "fuzz.example.org"; + int target_port = 12345; + + fwd.gateway_host = strdup_or_die("fuzz.example.org"); + fwd.gateway_port = 12345; + + fwd.type = SOCKS_4A; + socket = socks4_connect(&fwd, target_host, target_port, csp); + + if (JB_INVALID_SOCKET != socket) + { + fwd.type = SOCKS_5; + socket = socks5_connect(&fwd, target_host, target_port, csp); + } + + if (JB_INVALID_SOCKET == socket) + { + log_error(LOG_LEVEL_ERROR, "%s", csp->error_message); + return JB_ERR_PARSE; + } + + log_error(LOG_LEVEL_INFO, "Input looks like an acceptable socks response"); + + return JB_ERR_OK; + + } + #endif + /********************************************************************* * *************** *** 795,798 **** --- 840,846 ---- c->dstip[3] = (unsigned char)((web_server_addr ) & 0xff); + #ifdef FUZZ_SOCKS + sfd = 0; + #else /* pass the request to the socks server */ sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp); *************** *** 824,828 **** close_socket(sfd); } ! else if (read_socket(sfd, buf, sizeof(buf)) != sizeof(*s)) { errstr = "SOCKS4 negotiation read failed."; --- 872,878 ---- close_socket(sfd); } ! else ! #endif ! if (read_socket(sfd, buf, sizeof(buf)) != sizeof(*s)) { errstr = "SOCKS4 negotiation read failed."; *************** *** 912,915 **** --- 962,966 ---- } + /********************************************************************* * *************** *** 990,993 **** --- 1041,1048 ---- } + #ifdef FUZZ_SOCKS + sfd = 0; + if (!err && read_socket(sfd, sbuf, 2) != 2) + #else /* pass the request to the socks server */ sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp); *************** *** 1016,1020 **** return(JB_INVALID_SOCKET); } - if (!data_is_available(sfd, csp->config->socket_timeout)) { --- 1071,1074 ---- *************** *** 1031,1034 **** --- 1085,1089 ---- if (!err && read_socket(sfd, sbuf, sizeof(sbuf)) != 2) + #endif { errstr = "SOCKS5 negotiation read failed"; *************** *** 1077,1080 **** --- 1132,1136 ---- cbuf[client_pos++] = (char)((target_port ) & 0xff); + #ifndef FUZZ_SOCKS if (write_socket(sfd, cbuf, client_pos)) { *************** *** 1137,1140 **** --- 1193,1197 ---- } } + #endif server_size = read_socket(sfd, sbuf, SIZE_SOCKS5_REPLY_IPV4); Index: jbsockets.c =================================================================== RCS file: /cvsroot/ijbswa/current/jbsockets.c,v retrieving revision 1.138 retrieving revision 1.139 diff -C2 -d -r1.138 -r1.139 *** jbsockets.c 27 Sep 2016 22:48:28 -0000 1.138 --- jbsockets.c 24 Dec 2016 16:00:49 -0000 1.139 *************** *** 595,598 **** --- 595,606 ---- } + #ifdef FUZZ + if (!daemon_mode && fd <= 3) + { + log_error(LOG_LEVEL_WRITING, "Pretending to write to socket %d: %N", fd, len, buf); + return 0; + } + #endif + log_error(LOG_LEVEL_WRITING, "to socket %d: %N", fd, len, buf); Index: pcrs.c =================================================================== RCS file: /cvsroot/ijbswa/current/pcrs.c,v retrieving revision 1.50 retrieving revision 1.51 diff -C2 -d -r1.50 -r1.51 *** pcrs.c 25 May 2016 10:50:28 -0000 1.50 --- pcrs.c 24 Dec 2016 16:00:49 -0000 1.51 *************** *** 183,186 **** --- 183,218 ---- + #ifdef FUZZ + /********************************************************************* + * + * Function : pcrs_compile_fuzzed_replacement + * + * Description : Wrapper around pcrs_compile_replacement() for + * fuzzing purposes. + * + * Parameters : + * 1 : replacement = replacement part of s/// operator + * in perl syntax + * 2 : errptr = pointer to an integer in which error + * conditions can be returned. + * + * Returns : pcrs_substitute data structure, or NULL if an + * error is encountered. In that case, *errptr has + * the reason. + * + *********************************************************************/ + extern pcrs_substitute *pcrs_compile_fuzzed_replacement(const char *replacement, int *errptr) + { + int capturecount = PCRS_MAX_SUBMATCHES; /* XXX: fuzzworthy? */ + int trivial_flag = 0; /* We don't want to fuzz strncpy() */ + + *errptr = 0; /* XXX: Should pcrs_compile_replacement() do this? */ + + return pcrs_compile_replacement(replacement, trivial_flag, capturecount, errptr); + + } + #endif + + /********************************************************************* * *************** *** 213,217 **** --- 245,256 ---- char *text; pcrs_substitute *r; + #ifdef FUZZ + static const char *replacement_stack; + static const size_t *length_stack; + static pcrs_substitute *r_stack; + replacement_stack = replacement; + length_stack = &length; + #endif i = k = l = quoted = 0; *************** *** 234,237 **** --- 273,280 ---- memset(r, '\0', sizeof(pcrs_substitute)); + #ifdef FUZZ + r_stack = r; + #endif + length = strlen(replacement); Index: jcc.c =================================================================== RCS file: /cvsroot/ijbswa/current/jcc.c,v retrieving revision 1.448 retrieving revision 1.449 diff -C2 -d -r1.448 -r1.449 *** jcc.c 24 Dec 2016 15:58:49 -0000 1.448 --- jcc.c 24 Dec 2016 16:00:49 -0000 1.449 *************** *** 179,182 **** --- 179,187 ---- #endif + #ifdef FUZZ + int process_fuzzed_input(char *fuzz_input_type, char *fuzz_input_file); + void show_fuzz_usage(const char *name); + #endif + #ifdef MUTEX_LOCKS_AVAILABLE /* *************** *** 1280,1284 **** do { ! if (!data_is_available(csp->cfd, csp->config->socket_timeout)) { if (socket_is_still_alive(csp->cfd)) --- 1285,1294 ---- do { ! if ( ! #ifdef FUZZ ! 0 == (csp->flags & CSP_FLAG_FUZZED_INPUT) && ! #endif ! !data_is_available(csp->cfd, csp->config->socket_timeout) ! ) { if (socket_is_still_alive(csp->cfd)) *************** *** 1465,1468 **** --- 1475,1552 ---- + #ifdef FUZZ + /********************************************************************* + * + * Function : fuzz_chunked_transfer_encoding + * + * Description : Treat the fuzzed input as chunked transfer encoding + * to check and dechunk. + * + * Parameters : + * 1 : csp = Used to store the data. + * 2 : fuzz_input_file = File to read the input from. + * + * Returns : Result of dechunking + * + *********************************************************************/ + extern int fuzz_chunked_transfer_encoding(struct client_state *csp, char *fuzz_input_file) + { + size_t length; + size_t size = (size_t)(csp->iob->eod - csp->iob->cur); + enum chunk_status status; + + status = chunked_body_is_complete(csp->iob, &length); + if (CHUNK_STATUS_BODY_COMPLETE != status) + { + log_error(LOG_LEVEL_INFO, "Chunked body is incomplete or invalid"); + } + + return (JB_ERR_OK == remove_chunked_transfer_coding(csp->iob->cur, &size)); + + } + + + /********************************************************************* + * + * Function : fuzz_client_request + * + * Description : Try to get a client request from the fuzzed input. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : fuzz_input_file = File to read the input from. + * + * Returns : Result of fuzzing. + * + *********************************************************************/ + extern int fuzz_client_request(struct client_state *csp, char *fuzz_input_file) + { + jb_err err; + + csp->cfd = 0; + csp->ip_addr_str = "fuzzer"; + + if (strcmp(fuzz_input_file, "-") != 0) + { + log_error(LOG_LEVEL_FATAL, + "Fuzzed client requests can currenty only be read from stdin (-)."); + } + err = receive_client_request(csp); + if (err != JB_ERR_OK) + { + return 1; + } + err = parse_client_request(csp); + if (err != JB_ERR_OK) + { + return 1; + } + + return 0; + + } + #endif /* def FUZZ */ + + #ifdef FEATURE_FORCE_LOAD /********************************************************************* *************** *** 2540,2543 **** --- 2624,2628 ---- } + /********************************************************************* * *************** *** 2829,2832 **** --- 2914,2977 ---- + #ifdef FUZZ + /********************************************************************* + * + * Function : fuzz_server_response + * + * Description : Treat the input as a whole server response. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : fuzz_input_file = File to read the input from. + * + * Returns : 0 + * + *********************************************************************/ + extern int fuzz_server_response(struct client_state *csp, char *fuzz_input_file) + { + static struct forward_spec fwd; /* Zero'd due to being static */ + csp->cfd = 0; + + if (strcmp(fuzz_input_file, "-") == 0) + { + /* XXX: Doesn'T work yet. */ + csp->server_connection.sfd = 0; + } + else + { + csp->server_connection.sfd = open(fuzz_input_file, O_RDONLY); + if (csp->server_connection.sfd == -1) + { + log_error(LOG_LEVEL_FATAL, "Failed to open %s: %E", + fuzz_input_file); + } + } + csp->content_type |= CT_GIF; + csp->action->flags |= ACTION_DEANIMATE; + csp->action->string[ACTION_STRING_DEANIMATE] = "last"; + + csp->http->path = strdup_or_die("/"); + csp->http->host = strdup_or_die("fuzz.example.org"); + csp->http->hostport = strdup_or_die("fuzz.example.org:80"); + /* Prevent client socket monitoring */ + csp->flags |= CSP_FLAG_PIPELINED_REQUEST_WAITING; + csp->flags |= CSP_FLAG_CHUNKED; + + csp->config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; + csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; + + csp->content_type |= CT_DECLARED|CT_GIF; + + csp->config->socket_timeout = 0; + + cgi_init_error_messages(); + + handle_established_connection(csp, &fwd); + + return 0; + } + #endif + + #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* *************** *** 3159,3163 **** * *********************************************************************/ ! static void usage(const char *myname) { printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n" --- 3304,3308 ---- * *********************************************************************/ ! static void usage(const char *name) { printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n" *************** *** 3170,3175 **** "[--no-daemon] [--pidfile pidfile] [--pre-chroot-nslookup hostname] [--user user[.group]] " #endif /* defined(unix) */ ! "[--version] [configfile]\n" ! "Aborting\n", myname); exit(2); --- 3315,3326 ---- "[--no-daemon] [--pidfile pidfile] [--pre-chroot-nslookup hostname] [--user user[.group]] " #endif /* defined(unix) */ ! "[--version] [configfile]\n", ! name); ! ! #ifdef FUZZ ! show_fuzz_usage(name); ! #endif ! ! printf("Aborting\n"); exit(2); *************** *** 3327,3331 **** } - /********************************************************************* * --- 3478,3481 ---- *************** *** 3366,3369 **** --- 3516,3523 ---- char *pre_chroot_nslookup_to_load_resolver = NULL; #endif + #ifdef FUZZ + char *fuzz_input_type = NULL; + char *fuzz_input_file = NULL; + #endif Argc = argc; *************** *** 3493,3497 **** do_config_test = 1; } ! else if (argc_pos + 1 != argc) { --- 3647,3664 ---- do_config_test = 1; } ! #ifdef FUZZ ! else if (strcmp(argv[argc_pos], "--fuzz") == 0) ! { ! argc_pos++; ! if (argc < argc_pos + 2) usage(argv[0]); ! fuzz_input_type = argv[argc_pos]; ! argc_pos++; ! fuzz_input_file = argv[argc_pos]; ! } ! else if (strcmp(argv[argc_pos], "--stfu") == 0) ! { ! set_debug_level(LOG_LEVEL_STFU); ! } ! #endif else if (argc_pos + 1 != argc) { *************** *** 3597,3600 **** --- 3764,3774 ---- #endif /* def _WIN32 */ + #ifdef FUZZ + if (fuzz_input_type != NULL) + { + exit(process_fuzzed_input(fuzz_input_type, fuzz_input_file)); + } + #endif + if (do_config_test) { Index: errlog.h =================================================================== RCS file: /cvsroot/ijbswa/current/errlog.h,v retrieving revision 1.30 retrieving revision 1.31 diff -C2 -d -r1.30 -r1.31 *** errlog.h 24 Nov 2013 14:23:28 -0000 1.30 --- errlog.h 24 Dec 2016 16:00:49 -0000 1.31 *************** *** 56,59 **** --- 56,67 ---- #define LOG_LEVEL_RECEIVED 0x8000 #define LOG_LEVEL_ACTIONS 0x10000 + #ifdef FUZZ + /* + * Permanently disables logging through log_error(). + * Useful to reduce pointless overhead when fuzzing + * without watching stdout. + */ + #define LOG_LEVEL_STFU 0x20000 + #endif /* Following are always on: */ Index: urlmatch.c =================================================================== RCS file: /cvsroot/ijbswa/current/urlmatch.c,v retrieving revision 1.88 retrieving revision 1.89 diff -C2 -d -r1.88 -r1.89 *** urlmatch.c 17 Mar 2016 10:40:53 -0000 1.88 --- urlmatch.c 24 Dec 2016 16:00:49 -0000 1.89 *************** *** 625,633 **** { int errcode; - char rebuf[BUFFER_SIZE]; const char *fmt = NULL; assert(pattern); - assert(strlen(pattern) < sizeof(rebuf) - 2); if (pattern[0] == '\0') --- 625,633 ---- { int errcode; const char *fmt = NULL; + char *rebuf; + size_t rebuf_size; assert(pattern); if (pattern[0] == '\0') *************** *** 655,662 **** "Invalid anchoring in compile_pattern %d", anchoring); } ! *regex = zalloc_or_die(sizeof(**regex)); ! snprintf(rebuf, sizeof(rebuf), fmt, pattern); errcode = regcomp(*regex, rebuf, (REG_EXTENDED|REG_NOSUB|REG_ICASE)); --- 655,663 ---- "Invalid anchoring in compile_pattern %d", anchoring); } ! rebuf_size = strlen(pattern) + strlen(fmt); ! rebuf = malloc_or_die(rebuf_size); *regex = zalloc_or_die(sizeof(**regex)); ! snprintf(rebuf, rebuf_size, fmt, pattern); errcode = regcomp(*regex, rebuf, (REG_EXTENDED|REG_NOSUB|REG_ICASE)); *************** *** 664,671 **** if (errcode) { ! size_t errlen = regerror(errcode, *regex, rebuf, sizeof(rebuf)); ! if (errlen > (sizeof(rebuf) - (size_t)1)) { ! errlen = sizeof(rebuf) - (size_t)1; } rebuf[errlen] = '\0'; --- 665,672 ---- if (errcode) { ! size_t errlen = regerror(errcode, *regex, rebuf, rebuf_size); ! if (errlen > (rebuf_size - (size_t)1)) { ! errlen = rebuf_size - (size_t)1; } rebuf[errlen] = '\0'; *************** *** 673,679 **** --- 674,682 ---- pattern, url->spec, rebuf); free_pattern_spec(url); + freez(rebuf); return JB_ERR_PARSE; } + freez(rebuf); return JB_ERR_OK; Index: filters.h =================================================================== RCS file: /cvsroot/ijbswa/current/filters.h,v retrieving revision 1.47 retrieving revision 1.48 diff -C2 -d -r1.47 -r1.48 *** filters.h 17 Mar 2016 10:40:53 -0000 1.47 --- filters.h 24 Dec 2016 16:00:49 -0000 1.48 *************** *** 112,115 **** --- 112,120 ---- extern const char filters_h_rcs[]; + #ifdef FUZZ + extern char *gif_deanimate_response(struct client_state *csp); + extern jb_err remove_chunked_transfer_coding(char *buffer, size_t *size); + #endif + #endif /* ndef FILTERS_H_INCLUDED */ Index: errlog.c =================================================================== RCS file: /cvsroot/ijbswa/current/errlog.c,v retrieving revision 1.126 retrieving revision 1.127 diff -C2 -d -r1.126 -r1.127 *** errlog.c 26 Feb 2016 12:29:38 -0000 1.126 --- errlog.c 24 Dec 2016 16:00:49 -0000 1.127 *************** *** 246,249 **** --- 246,260 ---- void set_debug_level(int debug_level) { + #ifdef FUZZ + if (LOG_LEVEL_STFU == debug_level) + { + debug = LOG_LEVEL_STFU; + } + if (LOG_LEVEL_STFU == debug) + { + return; + } + #endif + debug = debug_level | LOG_LEVEL_MINIMUM; } *************** *** 701,704 **** --- 712,721 ---- ) { + #ifdef FUZZ + if (debug == LOG_LEVEL_STFU) + { + return; + } + #endif if (loglevel == LOG_LEVEL_FATAL) { Index: jcc.h =================================================================== RCS file: /cvsroot/ijbswa/current/jcc.h,v retrieving revision 1.36 retrieving revision 1.37 diff -C2 -d -r1.36 -r1.37 *** jcc.h 17 Mar 2016 10:40:53 -0000 1.36 --- jcc.h 24 Dec 2016 16:00:49 -0000 1.37 *************** *** 118,121 **** --- 118,127 ---- extern const char jcc_h_rcs[]; + #ifdef FUZZ + extern int fuzz_client_request(struct client_state *csp, char *fuzz_input_file); + extern int fuzz_server_response(struct client_state *csp, char *fuzz_input_file); + extern int fuzz_chunked_transfer_encoding(struct client_state *csp, char *fuzz_input_file); + #endif + #endif /* ndef JCC_H_INCLUDED */ Index: parsers.c =================================================================== RCS file: /cvsroot/ijbswa/current/parsers.c,v retrieving revision 1.310 retrieving revision 1.311 diff -C2 -d -r1.310 -r1.311 *** parsers.c 9 Dec 2016 09:13:19 -0000 1.310 --- parsers.c 24 Dec 2016 16:00:49 -0000 1.311 *************** *** 422,427 **** --- 422,432 ---- z_stream zstr; /* used by calls to zlib */ + #ifdef FUZZ + assert(csp->iob->cur - csp->iob->buf >= 0); + assert(csp->iob->eod - csp->iob->cur >= 0); + #else assert(csp->iob->cur - csp->iob->buf > 0); assert(csp->iob->eod - csp->iob->cur > 0); + #endif bufsize = csp->iob->size; *************** *** 719,723 **** * consistency conditions. */ ! if ((csp->iob->buf < csp->iob->cur) && (csp->iob->cur <= csp->iob->eod) && (csp->iob->eod <= csp->iob->buf + csp->iob->size)) --- 724,728 ---- * consistency conditions. */ ! if ((csp->iob->buf <= csp->iob->cur) && (csp->iob->cur <= csp->iob->eod) && (csp->iob->eod <= csp->iob->buf + csp->iob->size)) Index: filters.c =================================================================== RCS file: /cvsroot/ijbswa/current/filters.c,v retrieving revision 1.202 retrieving revision 1.203 diff -C2 -d -r1.202 -r1.203 *** filters.c 25 May 2016 10:50:55 -0000 1.202 --- filters.c 24 Dec 2016 16:00:49 -0000 1.203 *************** *** 83,87 **** typedef char *(*filter_function_ptr)(); static filter_function_ptr get_filter_function(const struct client_state *csp); - static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size); static jb_err prepare_for_filtering(struct client_state *csp); static void apply_url_actions(struct current_action_spec *action, --- 83,86 ---- *************** *** 1958,1962 **** --- 1957,1965 ---- * *********************************************************************/ + #ifdef FUZZ + char *gif_deanimate_response(struct client_state *csp) + #else static char *gif_deanimate_response(struct client_state *csp) + #endif { struct binbuffer *in, *out; *************** *** 2056,2060 **** --- 2059,2067 ---- * *********************************************************************/ + #ifdef FUZZ + extern jb_err remove_chunked_transfer_coding(char *buffer, size_t *size) + #else static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size) + #endif { size_t newsize = 0; *************** *** 2063,2066 **** --- 2070,2079 ---- const char *end_of_buffer = buffer + *size; + if (*size == 0) + { + log_error(LOG_LEVEL_FATAL, "Invalid chunked input. Buffer is empty."); + return JB_ERR_PARSE; + } + assert(buffer); from_p = to_p = buffer; Index: actions.h =================================================================== RCS file: /cvsroot/ijbswa/current/actions.h,v retrieving revision 1.24 retrieving revision 1.25 diff -C2 -d -r1.24 -r1.25 *** actions.h 24 Nov 2013 14:27:27 -0000 1.24 --- actions.h 24 Dec 2016 16:00:49 -0000 1.25 *************** *** 79,82 **** --- 79,85 ---- extern void unload_actions_file(void *file_data); extern int load_action_files(struct client_state *csp); + #ifdef FUZZ + extern int load_one_actions_file(struct client_state *csp, int fileid); + #endif #ifdef FEATURE_GRACEFUL_TERMINATION Index: actions.c =================================================================== RCS file: /cvsroot/ijbswa/current/actions.c,v retrieving revision 1.97 retrieving revision 1.98 diff -C2 -d -r1.97 -r1.98 *** actions.c 3 May 2016 13:20:37 -0000 1.97 --- actions.c 24 Dec 2016 16:00:49 -0000 1.98 *************** *** 125,129 **** ! static int load_one_actions_file(struct client_state *csp, int fileid); --- 125,132 ---- ! #ifndef FUZZ ! static ! #endif ! int load_one_actions_file(struct client_state *csp, int fileid); *************** *** 1211,1215 **** * *********************************************************************/ ! static int load_one_actions_file(struct client_state *csp, int fileid) { --- 1214,1221 ---- * *********************************************************************/ ! #ifndef FUZZ ! static ! #endif ! int load_one_actions_file(struct client_state *csp, int fileid) { ------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today.http://sdm.link/intel