Browse Source

Merge remote-tracking branch 'origin/maint-0.2.3'

Nick Mathewson 11 years ago
parent
commit
f8a665c87d
6 changed files with 38 additions and 18 deletions
  1. 5 0
      changes/bug6811
  2. 13 14
      src/common/util.c
  3. 1 1
      src/common/util.h
  4. 2 1
      src/or/directory.c
  5. 4 2
      src/or/dirvote.c
  6. 13 0
      src/test/test_util.c

+ 5 - 0
changes/bug6811

@@ -0,0 +1,5 @@
+  o Major security fixes:
+    - Fix an assertion failure in tor_timegm that could be triggered
+      by a badly formatted directory object.  Bug found by fuzzing with
+      Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc.
+      

+ 13 - 14
src/common/util.c

@@ -1315,11 +1315,11 @@ n_leapdays(int y1, int y2)
 static const int days_per_month[] =
   { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
-/** Return a time_t given a struct tm.  The result is given in GMT, and
- * does not account for leap seconds.
+/** Compute a time_t given a struct tm.  The result is given in GMT, and
+ * does not account for leap seconds.  Return 0 on success, -1 on failure.
  */
-time_t
-tor_timegm(struct tm *tm)
+int
+tor_timegm(const struct tm *tm, time_t *time_out)
 {
   /* This is a pretty ironclad timegm implementation, snarfed from Python2.2.
    * It's way more brute-force than fiddling with tzset().
@@ -1327,11 +1327,11 @@ tor_timegm(struct tm *tm)
   time_t year, days, hours, minutes, seconds;
   int i;
   year = tm->tm_year + 1900;
-  if (year < 1970 || tm->tm_mon < 0 || tm->tm_mon > 11) {
+  if (year < 1970 || tm->tm_mon < 0 || tm->tm_mon > 11 ||
+      tm->tm_year >= INT32_MAX-1900) {
     log_warn(LD_BUG, "Out-of-range argument to tor_timegm");
     return -1;
   }
-  tor_assert(year < INT_MAX);
   days = 365 * (year-1970) + n_leapdays(1970,(int)year);
   for (i = 0; i < tm->tm_mon; ++i)
     days += days_per_month[i];
@@ -1342,7 +1342,8 @@ tor_timegm(struct tm *tm)
 
   minutes = hours*60 + tm->tm_min;
   seconds = minutes*60 + tm->tm_sec;
-  return seconds;
+  *time_out = seconds;
+  return 0;
 }
 
 /* strftime is locale-specific, so we need to replace those parts */
@@ -1402,7 +1403,7 @@ parse_rfc1123_time(const char *buf, time_t *t)
     return -1;
   }
   if (tm_mday < 1 || tm_mday > 31 || tm_hour > 23 || tm_min > 59 ||
-      tm_sec > 60) {
+      tm_sec > 60 || tm_year >= INT32_MAX || tm_year < 1970) {
     char *esc = esc_for_log(buf);
     log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc);
     tor_free(esc);
@@ -1438,8 +1439,7 @@ parse_rfc1123_time(const char *buf, time_t *t)
   }
   tm.tm_year -= 1900;
 
-  *t = tor_timegm(&tm);
-  return 0;
+  return tor_timegm(&tm, t);
 }
 
 /** Set <b>buf</b> to the ISO8601 encoding of the local value of <b>t</b>.
@@ -1501,13 +1501,13 @@ parse_iso_time(const char *cp, time_t *t)
     return -1;
   }
   if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
-          hour > 23 || minute > 59 || second > 60) {
+          hour > 23 || minute > 59 || second > 60 || year >= INT32_MAX) {
     char *esc = esc_for_log(cp);
     log_warn(LD_GENERAL, "ISO time %s was nonsensical", esc);
     tor_free(esc);
     return -1;
   }
-  st_tm.tm_year = year-1900;
+  st_tm.tm_year = (int)year-1900;
   st_tm.tm_mon = month-1;
   st_tm.tm_mday = day;
   st_tm.tm_hour = hour;
@@ -1520,8 +1520,7 @@ parse_iso_time(const char *cp, time_t *t)
     tor_free(esc);
     return -1;
   }
-  *t = tor_timegm(&st_tm);
-  return 0;
+  return tor_timegm(&st_tm, t);
 }
 
 /** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh),

+ 1 - 1
src/common/util.h

@@ -244,7 +244,7 @@ int64_t tv_to_msec(const struct timeval *tv);
 int64_t tv_to_usec(const struct timeval *tv);
 long tv_udiff(const struct timeval *start, const struct timeval *end);
 long tv_mdiff(const struct timeval *start, const struct timeval *end);
-time_t tor_timegm(struct tm *tm);
+int tor_timegm(const struct tm *tm, time_t *time_out);
 #define RFC1123_TIME_LEN 29
 void format_rfc1123_time(char *buf, time_t t);
 int parse_rfc1123_time(const char *buf, time_t *t);

+ 2 - 1
src/or/directory.c

@@ -2619,7 +2619,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
   if ((header = http_get_header(headers, "If-Modified-Since: "))) {
     struct tm tm;
     if (parse_http_time(header, &tm) == 0) {
-      if_modified_since = tor_timegm(&tm);
+      if (tor_timegm(&tm, &if_modified_since)<0)
+        if_modified_since = 0;
     }
     /* The correct behavior on a malformed If-Modified-Since header is to
      * act as if no If-Modified-Since header had been given. */

+ 4 - 2
src/or/dirvote.c

@@ -2546,7 +2546,7 @@ time_t
 dirvote_get_start_of_next_interval(time_t now, int interval)
 {
   struct tm tm;
-  time_t midnight_today;
+  time_t midnight_today=0;
   time_t midnight_tomorrow;
   time_t next;
 
@@ -2555,7 +2555,9 @@ dirvote_get_start_of_next_interval(time_t now, int interval)
   tm.tm_min = 0;
   tm.tm_sec = 0;
 
-  midnight_today = tor_timegm(&tm);
+  if (tor_timegm(&tm, &midnight_today) < 0) {
+    log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight.");
+  }
   midnight_tomorrow = midnight_today + (24*60*60);
 
   next = midnight_today + ((now-midnight_today)/interval + 1)*interval;

+ 13 - 0
src/test/test_util.c

@@ -18,6 +18,19 @@
 #include <tchar.h>
 #endif
 
+/* XXXX this is a minimal wrapper to make the unit tests compile with the
+ * changed tor_timegm interface. */
+static time_t
+tor_timegm_wrapper(const struct tm *tm)
+{
+  time_t t;
+  if (tor_timegm(tm, &t) < 0)
+    return -1;
+  return t;
+}
+
+#define tor_timegm tor_timegm_wrapper
+
 static void
 test_util_time(void)
 {