[tor-commits] [tor/master] Avoid integer underflow in tor_version_compare.

nickm at torproject.org nickm at torproject.org
Wed Feb 15 12:51:16 UTC 2017


commit 194e31057fbf07d6bdf4b62d26e1a9db334e5f1c
Author: Nick Mathewson <nickm at torproject.org>
Date:   Tue Feb 7 10:58:02 2017 -0500

    Avoid integer underflow in tor_version_compare.
    
    Fix for TROVE-2017-001 and bug 21278.
    
    (Note: Instead of handling signed ints "correctly", we keep the old
    behavior, except for the part where we would crash with -ftrapv.)
---
 changes/trove-2017-001.2 |  8 ++++++++
 src/or/routerparse.c     | 49 +++++++++++++++++++++++++++++-------------------
 2 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/changes/trove-2017-001.2 b/changes/trove-2017-001.2
new file mode 100644
index 0000000..3ef073c
--- /dev/null
+++ b/changes/trove-2017-001.2
@@ -0,0 +1,8 @@
+  o Major bugfixes (parsing):
+    - Fix an integer underflow bug when comparing malformed Tor versions.
+      This bug is harmless, except when Tor has been built with
+      --enable-expensive-hardening, which would turn it into a crash;
+      or on Tor 0.2.9.1-alpha through Tor 0.2.9.8, which were built with
+      -ftrapv by default.
+      Part of TROVE-2017-001. Fixes bug 21278; bugfix on
+      0.0.8pre1. Found by OSS-Fuzz.
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 71373ce..1243035 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -4545,26 +4545,37 @@ tor_version_compare(tor_version_t *a, tor_version_t *b)
   int i;
   tor_assert(a);
   tor_assert(b);
-  if ((i = a->major - b->major))
-    return i;
-  else if ((i = a->minor - b->minor))
-    return i;
-  else if ((i = a->micro - b->micro))
-    return i;
-  else if ((i = a->status - b->status))
-    return i;
-  else if ((i = a->patchlevel - b->patchlevel))
-    return i;
-  else if ((i = strcmp(a->status_tag, b->status_tag)))
-    return i;
-  else if ((i = a->svn_revision - b->svn_revision))
-    return i;
-  else if ((i = a->git_tag_len - b->git_tag_len))
-    return i;
-  else if (a->git_tag_len)
-    return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
+
+  /* We take this approach to comparison to ensure the same (bogus!) behavior
+   * on all inputs as we would have seen before bug #21278 was fixed. The
+   * only important difference here is that this method doesn't cause
+   * a signed integer underflow.
+   */
+#define CMP(field) do {                               \
+    unsigned aval = (unsigned) a->field;              \
+    unsigned bval = (unsigned) b->field;              \
+    int result = (int) (aval - bval);                 \
+    if (result < 0)                                   \
+      return -1;                                      \
+    else if (result > 0)                              \
+      return 1;                                       \
+  } while (0)
+
+  CMP(major);
+  CMP(minor);
+  CMP(micro);
+  CMP(status);
+  CMP(patchlevel);
+  if ((i = strcmp(a->status_tag, b->status_tag)))
+     return i;
+  CMP(svn_revision);
+  CMP(git_tag_len);
+  if (a->git_tag_len)
+     return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
   else
-    return 0;
+     return 0;
+
+#undef CMP
 }
 
 /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.





More information about the tor-commits mailing list