From: Fabian Keil Date: Sun, 9 Dec 2012 12:27:01 +0000 (+0000) Subject: Optionally let parse_header_time() sanity check strptime() results before trusting... X-Git-Tag: v_3_0_20~142 X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=commitdiff_plain;h=21ea098609f18d524ca41b90b48d037f0703e04e Optionally let parse_header_time() sanity check strptime() results before trusting them Broken strptime() implementations have caused problems in the past and the most recent offender seems to be FreeBSD's libc: http://www.freebsd.org/cgi/query-pr.cgi?pr=173421 --- diff --git a/acconfig.h b/acconfig.h index c7dfab6e..286ff629 100644 --- a/acconfig.h +++ b/acconfig.h @@ -181,6 +181,11 @@ */ #undef FEATURE_STATISTICS +/* + * Enable strptime() sanity checks. + */ +#undef FEATURE_STRPTIME_SANITY_CHECKS + /* * Allow Privoxy to be "disabled" so it is just a normal non-blocking * non-anonymizing proxy. This is useful if you're trying to access a diff --git a/configure.in b/configure.in index 16bbcc42..3194fe60 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. dnl -dnl $Id: configure.in,v 1.173 2012/10/12 11:15:17 fabiankeil Exp $ +dnl $Id: configure.in,v 1.174 2012/10/12 11:17:48 fabiankeil Exp $ dnl dnl Written by and Copyright (C) 2001-2010 the dnl Privoxy team. http://www.privoxy.org/ @@ -32,7 +32,7 @@ dnl ================================================================= dnl AutoConf Initialization dnl ================================================================= -AC_REVISION($Revision: 1.173 $) +AC_REVISION($Revision: 1.174 $) AC_INIT(jcc.c) if test ! -f config.h.in; then @@ -968,6 +968,14 @@ AC_ARG_ENABLE(accept-filter, AC_DEFINE(FEATURE_ACCEPT_FILTER) fi]) +AC_ARG_ENABLE(strptime-sanity-checks, +[ --enable-strptime-sanity-checks Only trust strptime() results if an additional strftime()/strptime() + conversion doesn't change the result. Can be useful if strptime() is + known or suspected to be broken.], +[if test $enableval = yes; then + AC_DEFINE(FEATURE_STRPTIME_SANITY_CHECKS) +fi]) + dnl pcre/pcrs is needed for CGI anyway, so dnl the choice is only between static and dnl dynamic: diff --git a/parsers.c b/parsers.c index 069bbae0..47be9199 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.270 2012/12/07 12:43:55 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.271 2012/12/07 12:50:17 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -4212,6 +4212,44 @@ static jb_err parse_header_time(const char *header_time, time_t *result) continue; } *result = timegm(&gmt); + +#ifdef FEATURE_STRPTIME_SANITY_CHECKS + /* + * Verify that parsing the date recreated from the first + * parse operation gets the previous result. If it doesn't, + * either strptime() or strftime() are malfunctioning. + * + * We could string-compare the recreated date with the original + * header date, but this leads to false positives as strptime() + * may let %a accept all day formats while strftime() will only + * create one. + */ + { + char recreated_date[100]; + struct tm *tm; + time_t result2; + + tm = gmtime(result); + strftime(recreated_date, sizeof(recreated_date), time_formats[i], tm); + memset(&gmt, 0, sizeof(gmt)); + if (NULL == strptime(recreated_date, time_formats[i], &gmt)) + { + log_error(LOG_LEVEL_ERROR, + "Failed to parse '%s' generated with '%s' to recreate '%s'.", + recreated_date, time_formats[i], header_time); + continue; + } + result2 = timegm(&gmt); + if (*result != result2) + { + log_error(LOG_LEVEL_ERROR, "strftime() and strptime() disagree. " + "Format: '%s'. In: '%s', out: '%s'. %d != %d. Rejecting.", + time_formats[i], header_time, recreated_date, *result, result2); + continue; + } + } +#endif + return JB_ERR_OK; } }