fuzz.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /*********************************************************************
  2. *
  3. * File : $Source: /cvsroot/ijbswa/current/fuzz.c,v $
  4. *
  5. * Purpose : Fuzz-related functions for Privoxy.
  6. *
  7. * Copyright : Written by and Copyright (C) 2014-16 by
  8. * Fabian Keil <fk@fabiankeil.de>
  9. *
  10. * This program is free software; you can redistribute it
  11. * and/or modify it under the terms of the GNU General
  12. * Public License as published by the Free Software
  13. * Foundation; either version 2 of the License, or (at
  14. * your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will
  17. * be useful, but WITHOUT ANY WARRANTY; without even the
  18. * implied warranty of MERCHANTABILITY or FITNESS FOR A
  19. * PARTICULAR PURPOSE. See the GNU General Public
  20. * License for more details.
  21. *
  22. * The GNU General Public License should be included with
  23. * this file. If not, you can view it at
  24. * http://www.gnu.org/copyleft/gpl.html
  25. * or write to the Free Software Foundation, Inc., 59
  26. * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  27. *
  28. *********************************************************************/
  29. #include "config.h"
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <sys/types.h>
  33. #include <unistd.h>
  34. #include "project.h"
  35. #include "filters.h"
  36. #include "loaders.h"
  37. #include "parsers.h"
  38. #include "miscutil.h"
  39. #include "errlog.h"
  40. #include "actions.h"
  41. #include "cgi.h"
  42. #include "loadcfg.h"
  43. #include "urlmatch.h"
  44. #include "filters.h"
  45. #include "jbsockets.h"
  46. #include "gateway.h"
  47. #include "jcc.h"
  48. #include "list.h"
  49. #ifdef FUZZ
  50. static int fuzz_action(struct client_state *csp, char *fuzz_input_file);
  51. static int fuzz_client_header(struct client_state *csp, char *fuzz_input_file);
  52. static int fuzz_deflate(struct client_state *csp, char *fuzz_input_file);
  53. static int fuzz_filter(struct client_state *csp, char *fuzz_input_file);
  54. static int fuzz_gif(struct client_state *csp, char *fuzz_input_file);
  55. static int fuzz_gzip(struct client_state *csp, char *fuzz_input_file);
  56. static int fuzz_socks(struct client_state *csp, char *fuzz_input_file);
  57. static int fuzz_pcrs_substitute(struct client_state *csp, char *fuzz_input_file);
  58. static int fuzz_server_header(struct client_state *csp, char *fuzz_input_file);
  59. struct fuzz_mode
  60. {
  61. const char *name;
  62. const char *expected_input;
  63. const int stdin_support;
  64. int (* const handler)(struct client_state *csp, char *input_file);
  65. };
  66. static const struct fuzz_mode fuzz_modes[] = {
  67. { "action", "Text to parse as action file.", 0, fuzz_action },
  68. { "client-request", "Client request to parse. Currently incomplete", 1, fuzz_client_request },
  69. { "client-header", "Client header to parse.", 1, fuzz_client_header },
  70. { "chunked-transfer-encoding", "Chunk-encoded data to dechunk.", 1, fuzz_chunked_transfer_encoding },
  71. { "deflate", "deflate-compressed data to decompress.", 1, fuzz_deflate },
  72. { "filter", "Text to parse as filter file.", 0, fuzz_filter },
  73. { "gif", "gif to deanimate.", 1, fuzz_gif },
  74. { "gzip", "gzip-compressed data to decompress.", 1, fuzz_gzip },
  75. { "pcrs-substitute", "A pcrs-substitute to compile. Not a whole pcrs job! Example: Bla $1 bla \x43 $3 blah.", 1, fuzz_pcrs_substitute },
  76. { "server-header", "Server header to parse.", 1, fuzz_server_header },
  77. { "server-response", "Server response to parse.", 1, fuzz_server_response },
  78. { "socks", "A socks server response. Only reads from stdin!", 1, fuzz_socks },
  79. };
  80. /*********************************************************************
  81. *
  82. * Function : load_fuzz_input_from_stdin
  83. *
  84. * Description : Loads stdin into a buffer.
  85. *
  86. * Parameters :
  87. * 1 : csp = Used to store the data.
  88. *
  89. * Returns : JB_ERR_OK in case of success,
  90. *
  91. *********************************************************************/
  92. static jb_err load_fuzz_input_from_stdin(struct client_state *csp)
  93. {
  94. static char buf[BUFFER_SIZE];
  95. int ret;
  96. while (0 < (ret = read_socket(0, buf, sizeof(buf))))
  97. {
  98. log_error(LOG_LEVEL_INFO,
  99. "Got %d bytes from stdin: %E. They look like this: %N",
  100. ret, ret, buf);
  101. if (add_to_iob(csp->iob, csp->config->buffer_limit, buf, ret))
  102. {
  103. log_error(LOG_LEVEL_FATAL, "Failed to buffer them.");
  104. }
  105. }
  106. log_error(LOG_LEVEL_INFO, "Read %d bytes from stdin",
  107. csp->iob->eod -csp->iob->cur);
  108. return JB_ERR_OK;
  109. }
  110. /*********************************************************************
  111. *
  112. * Function : load_fuzz_input_from_file
  113. *
  114. * Description : Loads file content into a buffer.
  115. *
  116. * Parameters :
  117. * 1 : csp = Used to store the data.
  118. * 2 : filename = Name of the file to be loaded.
  119. *
  120. * Returns : JB_ERR_OK in case of success,
  121. *
  122. *********************************************************************/
  123. static jb_err load_fuzz_input_from_file(struct client_state *csp, const char *filename)
  124. {
  125. FILE *fp;
  126. size_t length;
  127. long ret;
  128. fp = fopen(filename, "rb");
  129. if (NULL == fp)
  130. {
  131. log_error(LOG_LEVEL_FATAL, "Failed to open %s: %E", filename);
  132. }
  133. /* Get file length */
  134. if (fseek(fp, 0, SEEK_END))
  135. {
  136. log_error(LOG_LEVEL_FATAL,
  137. "Unexpected error while fseek()ing to the end of %s: %E",
  138. filename);
  139. }
  140. ret = ftell(fp);
  141. if (-1 == ret)
  142. {
  143. log_error(LOG_LEVEL_FATAL,
  144. "Unexpected ftell() error while loading %s: %E",
  145. filename);
  146. }
  147. length = (size_t)ret;
  148. /* Go back to the beginning. */
  149. if (fseek(fp, 0, SEEK_SET))
  150. {
  151. log_error(LOG_LEVEL_FATAL,
  152. "Unexpected error while fseek()ing to the beginning of %s: %E",
  153. filename);
  154. }
  155. csp->iob->size = length + 1;
  156. csp->iob->buf = malloc_or_die(csp->iob->size);
  157. csp->iob->cur = csp->iob->buf;
  158. csp->iob->eod = csp->iob->buf + length;
  159. if (1 != fread(csp->iob->cur, length, 1, fp))
  160. {
  161. /*
  162. * May theoretically happen if the file size changes between
  163. * fseek() and fread() because it's edited in-place. Privoxy
  164. * and common text editors don't do that, thus we just fail.
  165. */
  166. log_error(LOG_LEVEL_FATAL,
  167. "Couldn't completely read file %s.", filename);
  168. }
  169. *csp->iob->eod = '\0';
  170. fclose(fp);
  171. return JB_ERR_OK;
  172. }
  173. /*********************************************************************
  174. *
  175. * Function : load_fuzz_input
  176. *
  177. * Description : Loads a file into a buffer. XXX: Reverse argument order
  178. *
  179. * Parameters :
  180. * 1 : csp = Used to store the data.
  181. * 2 : filename = Name of the file to be loaded.
  182. *
  183. * Returns : JB_ERR_OK in case of success,
  184. *
  185. *********************************************************************/
  186. jb_err load_fuzz_input(struct client_state *csp, const char *filename)
  187. {
  188. if (strcmp(filename, "-") == 0)
  189. {
  190. return load_fuzz_input_from_stdin(csp);
  191. }
  192. return load_fuzz_input_from_file(csp, filename);
  193. }
  194. /*********************************************************************
  195. *
  196. * Function : remove_forbidden_bytes
  197. *
  198. * Description : Sanitizes fuzzed data to decrease the likelihood of
  199. * premature parse abortions.
  200. *
  201. * Parameters :
  202. * 1 : csp = Used to store the data.
  203. *
  204. * Returns : N/A
  205. *
  206. *********************************************************************/
  207. static void remove_forbidden_bytes(struct client_state *csp)
  208. {
  209. char *p = csp->iob->cur;
  210. char first_valid_byte = ' ';
  211. while (p < csp->iob->eod)
  212. {
  213. if (*p != '\0')
  214. {
  215. first_valid_byte = *p;
  216. break;
  217. }
  218. p++;
  219. }
  220. p = csp->iob->cur;
  221. while (p < csp->iob->eod)
  222. {
  223. if (*p == '\0')
  224. {
  225. *p = first_valid_byte;
  226. }
  227. p++;
  228. }
  229. }
  230. /*********************************************************************
  231. *
  232. * Function : fuzz_action
  233. *
  234. * Description : Treat the fuzzed input as action file.
  235. *
  236. * Parameters :
  237. * 1 : csp = Used to store the data.
  238. * 2 : fuzz_input_file = File to read the input from.
  239. *
  240. * Returns : Result of fuzzed function
  241. *
  242. *********************************************************************/
  243. int fuzz_action(struct client_state *csp, char *fuzz_input_file)
  244. {
  245. csp->config->actions_file[0] = fuzz_input_file;
  246. return(load_action_files(csp));
  247. }
  248. /*********************************************************************
  249. *
  250. * Function : fuzz_client_header
  251. *
  252. * Description : Treat the fuzzed input as a client header.
  253. *
  254. * Parameters :
  255. * 1 : csp = Used to store the data.
  256. * 2 : fuzz_input_file = File to read the input from.
  257. *
  258. * Returns : Result of fuzzed function
  259. *
  260. *********************************************************************/
  261. int fuzz_client_header(struct client_state *csp, char *fuzz_input_file)
  262. {
  263. char *header;
  264. header = get_header(csp->iob);
  265. if (NULL == header)
  266. {
  267. return 1;
  268. }
  269. if (JB_ERR_OK != enlist(csp->headers, header))
  270. {
  271. return 1;
  272. }
  273. /*
  274. * Silence an insightful client_host_adder() warning
  275. * about ignored weirdness.
  276. */
  277. csp->flags |= CSP_FLAG_HOST_HEADER_IS_SET;
  278. /* Adding headers doesn't depend on the fuzzed input */
  279. csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET;
  280. /* +hide-if-modified-since{+60} */
  281. csp->action->flags |= ACTION_HIDE_IF_MODIFIED_SINCE;
  282. csp->action->string[ACTION_STRING_IF_MODIFIED_SINCE] = "+60";
  283. /* XXX: Enable more actions. */
  284. return(sed(csp, FILTER_CLIENT_HEADERS));
  285. }
  286. /*********************************************************************
  287. *
  288. * Function : fuzz_filter
  289. *
  290. * Description : Treat the fuzzed input as filter file.
  291. *
  292. * Parameters :
  293. * 1 : csp = Used to store the data.
  294. * 2 : fuzz_input_file = File to read the input from.
  295. *
  296. * Returns : Result of fuzzed function
  297. *
  298. *********************************************************************/
  299. int fuzz_filter(struct client_state *csp, char *fuzz_input_file)
  300. {
  301. csp->config->re_filterfile[0] = fuzz_input_file;
  302. return (load_one_re_filterfile(csp, 0));
  303. }
  304. /*********************************************************************
  305. *
  306. * Function : fuzz_deflate
  307. *
  308. * Description : Treat the fuzzed input as data to deflate.
  309. *
  310. * Parameters :
  311. * 1 : csp = Used to store the data.
  312. * 2 : fuzz_input_file = File to read the input from.
  313. *
  314. * Returns : Result of fuzzed function
  315. *
  316. *********************************************************************/
  317. static int fuzz_deflate(struct client_state *csp, char *fuzz_input_file)
  318. {
  319. csp->content_type = CT_DEFLATE;
  320. return(JB_ERR_OK == decompress_iob(csp));
  321. }
  322. /*********************************************************************
  323. *
  324. * Function : fuzz_gif
  325. *
  326. * Description : Treat the fuzzed input as a gif to deanimate.
  327. *
  328. * Parameters :
  329. * 1 : csp = Used to store the data.
  330. * 2 : fuzz_input_file = File to read the input from.
  331. *
  332. * Returns : Result of fuzzed function
  333. *
  334. *********************************************************************/
  335. static int fuzz_gif(struct client_state *csp, char *fuzz_input_file)
  336. {
  337. char *deanimated_gif;
  338. if (6 < csp->iob->size)
  339. {
  340. /* Why yes of course, officer, this is a gif. */
  341. memcpy(csp->iob->cur, "GIF87a", 6);
  342. }
  343. /* Using the last image requires parsing of all images */
  344. csp->action->string[ACTION_STRING_DEANIMATE] = "last";
  345. deanimated_gif = gif_deanimate_response(csp);
  346. if (NULL != deanimated_gif)
  347. {
  348. free(deanimated_gif);
  349. return 0;
  350. }
  351. return 1;
  352. }
  353. /*********************************************************************
  354. *
  355. * Function : fuzz_gzip
  356. *
  357. * Description : Treat the fuzzed input as data to unzip
  358. *
  359. * Parameters :
  360. * 1 : csp = Used to store the data.
  361. * 2 : fuzz_input_file = File to read the input from.
  362. *
  363. * Returns : Result of fuzzed function
  364. *
  365. *********************************************************************/
  366. static int fuzz_gzip(struct client_state *csp, char *fuzz_input_file)
  367. {
  368. csp->content_type = CT_GZIP;
  369. return(JB_ERR_OK == decompress_iob(csp));
  370. }
  371. /*********************************************************************
  372. *
  373. * Function : fuzz_socks
  374. *
  375. * Description : Treat the fuzzed input as a socks response.
  376. * XXX: This is pretty useless as parsing socks response
  377. * is trivial.
  378. *
  379. * Parameters :
  380. * 1 : csp = Used to store the data.
  381. * 2 : fuzz_input_file = File to read the input from.
  382. *
  383. * Returns : Result of fuzzed function
  384. *
  385. *********************************************************************/
  386. static int fuzz_socks(struct client_state *csp, char *fuzz_input_file)
  387. {
  388. return(JB_ERR_OK == socks_fuzz(csp));
  389. }
  390. /*********************************************************************
  391. *
  392. * Function : fuzz_pcrs_substitute
  393. *
  394. * Description : Treat the fuzzed input as a pcrs substitute.
  395. *
  396. * Parameters :
  397. * 1 : csp = Used to store the data.
  398. * 2 : fuzz_input_file = File to read the input from.
  399. *
  400. * Returns : Result of fuzzed function
  401. *
  402. *********************************************************************/
  403. static int fuzz_pcrs_substitute(struct client_state *csp, char *fuzz_input_file)
  404. {
  405. static pcrs_substitute *result;
  406. int err;
  407. remove_forbidden_bytes(csp);
  408. result = pcrs_compile_fuzzed_replacement(csp->iob->cur, &err);
  409. if (NULL == result)
  410. {
  411. log_error(LOG_LEVEL_ERROR,
  412. "Failed to compile pcrs replacement. Error: %s", pcrs_strerror(err));
  413. return 1;
  414. }
  415. log_error(LOG_LEVEL_INFO, "%s", pcrs_strerror(err));
  416. free(result->text);
  417. freez(result);
  418. return 0;
  419. }
  420. /*********************************************************************
  421. *
  422. * Function : fuzz_server_header
  423. *
  424. * Description : Treat the fuzzed input as a server header.
  425. *
  426. * Parameters :
  427. * 1 : csp = Used to store the data.
  428. * 2 : fuzz_input_file = File to read the input from.
  429. *
  430. * Returns : Result of fuzzed function
  431. *
  432. *********************************************************************/
  433. int fuzz_server_header(struct client_state *csp, char *fuzz_input_file)
  434. {
  435. char *header;
  436. header = get_header(csp->iob);
  437. if (NULL == header)
  438. {
  439. return 1;
  440. }
  441. if (JB_ERR_OK != enlist(csp->headers, header))
  442. {
  443. return 1;
  444. }
  445. /* Adding headers doesn't depend on the fuzzed input */
  446. csp->flags |= CSP_FLAG_CLIENT_HEADER_PARSING_DONE;
  447. csp->flags |= CSP_FLAG_SERVER_CONNECTION_HEADER_SET;
  448. /* +overwrite-last-modified{randomize} */
  449. csp->action->flags |= ACTION_OVERWRITE_LAST_MODIFIED;
  450. csp->action->string[ACTION_STRING_LAST_MODIFIED] = "randomize";
  451. /* +limit-cookie-lifetime{60} */
  452. csp->action->flags |= ACTION_LIMIT_COOKIE_LIFETIME;
  453. csp->action->string[ACTION_STRING_LIMIT_COOKIE_LIFETIME] = "60";
  454. /* XXX: Enable more actions. */
  455. return(sed(csp, FILTER_SERVER_HEADERS));
  456. }
  457. /*********************************************************************
  458. *
  459. * Function : process_fuzzed_input
  460. *
  461. * Description : Process the fuzzed input in a specified file treating
  462. * it like the input type specified.
  463. *
  464. * Parameters :
  465. * 1 : fuzz_input_type = Type of input.
  466. * 2 : fuzz_input_file = File to read the input from.
  467. *
  468. * Returns : Return value of the fuzzed function
  469. *
  470. *********************************************************************/
  471. int process_fuzzed_input(char *fuzz_input_type, char *fuzz_input_file)
  472. {
  473. static struct client_state csp_stack_storage;
  474. static struct configuration_spec config_stack_storage;
  475. struct client_state *csp;
  476. int i;
  477. csp = &csp_stack_storage;
  478. csp->config = &config_stack_storage;
  479. csp->config->buffer_limit = 4096 * 1024;
  480. csp->config->receive_buffer_size = 4096;
  481. /* In --stfu mode, these will be ignored ... */
  482. 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);
  483. csp->flags |= CSP_FLAG_FUZZED_INPUT;
  484. csp->config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
  485. #ifdef FEATURE_CLIENT_TAGS
  486. csp->config->trust_x_forwarded_for = 1;
  487. #endif
  488. for (i = 0; i < SZ(fuzz_modes); i++)
  489. {
  490. if (strcmp(fuzz_modes[i].name, fuzz_input_type) == 0)
  491. {
  492. if (fuzz_modes[i].stdin_support &&
  493. (strcmp(fuzz_input_type, "client-request") != 0) &&
  494. (strcmp(fuzz_input_type, "server-response") != 0) &&
  495. (strcmp(fuzz_input_type, "socks") != 0))
  496. {
  497. load_fuzz_input(csp, fuzz_input_file);
  498. }
  499. return (fuzz_modes[i].handler(csp, fuzz_input_file));
  500. }
  501. }
  502. log_error(LOG_LEVEL_FATAL,
  503. "Unrecognized fuzz type %s for input file %s. You may need --help.",
  504. fuzz_input_type, fuzz_input_file);
  505. /* Not reached. */
  506. return 1;
  507. }
  508. /*********************************************************************
  509. *
  510. * Function : show_fuzz_usage
  511. *
  512. * Description : Shows the --fuzz usage. D'oh.
  513. *
  514. * Parameters : Pointer to argv[0] for identifying ourselves
  515. *
  516. * Returns : void
  517. *
  518. *********************************************************************/
  519. void show_fuzz_usage(const char *name)
  520. {
  521. int i;
  522. printf("%s%s --fuzz fuzz-mode ./path/to/fuzzed/input [--stfu]\n\n",
  523. " ", name);
  524. printf("Supported fuzz modes and the expected input:\n");
  525. for (i = 0; i < SZ(fuzz_modes); i++)
  526. {
  527. printf(" %s: %s\n", fuzz_modes[i].name, fuzz_modes[i].expected_input);
  528. }
  529. printf("\n");
  530. printf("The following fuzz modes read data from stdin if the 'file' is '-'\n");
  531. for (i = 0; i < SZ(fuzz_modes); i++)
  532. {
  533. if (fuzz_modes[i].stdin_support)
  534. {
  535. printf(" %s\n", fuzz_modes[i].name);
  536. }
  537. }
  538. printf("\n");
  539. }
  540. #endif