]> granicus.if.org Git - libevent/commitdiff
Fix UB in evutil_date_rfc1123()
authorAzat Khuzhin <a3at.mail@gmail.com>
Mon, 19 Dec 2016 07:22:51 +0000 (10:22 +0300)
committerAzat Khuzhin <a3at.mail@gmail.com>
Thu, 22 Dec 2016 11:46:38 +0000 (14:46 +0300)
As pointed in https://github.com/libevent/libevent/pull/417#issuecomment-267860738
  "code is unsafe because in evutil_date_rfc1123() the pointer to the
  automatic variable struct tm cur is used outside the scope it defined."

Checked with `clang -fsanitize=address -fsanitize-address-use-after-scope`
and test that call evutil_date_rfc1123() with tm==NULL

evutil_time.c
include/event2/util.h
test/regress_util.c

index 3a8424ea3c7f4ec590c088807709fe183ac57a63..da5c745375ae5966c0cff55cf7ef65c0ec52baee 100644 (file)
@@ -146,7 +146,8 @@ evutil_usleep_(const struct timeval *tv)
 }
 
 int
-evutil_date_rfc1123(char *date, const size_t datelen, struct tm *cur_p) {
+evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm)
+{
        static const char *DAYS[] =
                { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
        static const char *MONTHS[] =
@@ -154,23 +155,24 @@ evutil_date_rfc1123(char *date, const size_t datelen, struct tm *cur_p) {
 
        time_t t = time(NULL);
 
-       /* If `cur_p` is null, set system's current time. */
-       if (cur_p == NULL) {
+#ifndef _WIN32
+       struct tm sys;
+#endif
+
+       /* If `tm` is null, set system's current time. */
+       if (tm == NULL) {
 #ifdef _WIN32
-               cur_p = gmtime(&t);
+               tm = gmtime(&t);
 #else
-               {
-                       struct tm cur;
-                       gmtime_r(&t, &cur);
-                       cur_p = &cur;
-               }
+               gmtime_r(&t, &sys);
+               tm = &sys;
 #endif
        }
 
        return evutil_snprintf(
                date, datelen, "%s, %02d %s %4d %02d:%02d:%02d GMT",
-               DAYS[cur_p->tm_wday], cur_p->tm_mday, MONTHS[cur_p->tm_mon],
-               1900+cur_p->tm_year, cur_p->tm_hour, cur_p->tm_min, cur_p->tm_sec);
+               DAYS[tm->tm_wday], tm->tm_mday, MONTHS[tm->tm_mon],
+               1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
 }
 
 /*
index defe00a3a65ed450bb3b70e6ab50176992749e3a..dd4bbb69d081d45f095a01f634cac2b26c66e515 100644 (file)
@@ -334,13 +334,13 @@ struct evutil_monotonic_timer
 #define EV_MONOT_FALLBACK 2
 
 /** Format a date string using RFC 1123 format (used in HTTP).
- * If `cur_p` is NULL, current system's time will be used.
+ * If `tm` is NULL, current system's time will be used.
  * The number of characters written will be returned.
  * One should check if the return value is smaller than `datelen` to check if
  * the result is truncated or not.
  */
-EVENT2_EXPORT_SYMBOL
-int evutil_date_rfc1123(char *date, const size_t datelen, struct tm *cur_p);
+EVENT2_EXPORT_SYMBOL int
+evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm);
 
 /** Allocate a new struct evutil_monotonic_timer for use with the
  * evutil_configure_monotonic_time() and evutil_gettime_monotonic()
index 0a57f7ce6bb94d5fbb5c2a84055b5510894ab315..12f76e61016abd85df38738ac91997c73c1606e2 100644 (file)
@@ -1418,6 +1418,7 @@ test_evutil_date_rfc1123(void *arg)
 {
        struct tm query;
        char result[30];
+       size_t i = 0;
 
        /* Checks if too small buffers are safely accepted. */
        {
@@ -1427,7 +1428,7 @@ test_evutil_date_rfc1123(void *arg)
        }
 
        /* Checks for testcases. */
-       for (size_t i=0; ; i++) {
+       for (i = 0; ; i++) {
                struct date_rfc1123_case c = date_rfc1123_cases[i];
 
                if (strlen(c.date) == 0)