Blob Blame History Raw
From 73b65b02d5d1aa4612bb7015f80c8cd1b5e828cd Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 18 Mar 2016 17:14:32 +0100
Subject: [PATCH] Fix CVE-2016-2315 CVE-2016-2324

- added upstream macros for detecting size_t overflow (much more just
  for easier related changes in future, if we want to do some yet)
- upstream solution removes function path_name() and modify all related
  part of code to replace this function. However, it's too hard for
  backport to such old version of git without unchanged behaviour,
  so application just die with error message instead.
---
 diff.h            |  4 ++--
 git-compat-util.h | 35 +++++++++++++++++++++++++++++++++++
 revision.c        | 13 ++++++++++---
 3 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/diff.h b/diff.h
index ce123fa..88db230 100644
--- a/diff.h
+++ b/diff.h
@@ -209,8 +209,8 @@ struct combine_diff_path {
 	} parent[FLEX_ARRAY];
 };
 #define combine_diff_path_size(n, l) \
-	(sizeof(struct combine_diff_path) + \
-	 sizeof(struct combine_diff_parent) * (n) + (l) + 1)
+	st_add4(sizeof(struct combine_diff_path), (l), 1, \
+		st_mult(sizeof(struct combine_diff_parent), (n)))
 
 extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
 			      int dense, struct rev_info *);
diff --git a/git-compat-util.h b/git-compat-util.h
index d493a8c..d5a15fa 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -46,6 +46,14 @@
 #define unsigned_add_overflows(a, b) \
     ((b) > maximum_unsigned_value_of_type(a) - (a))
 
+/*
+ * Returns true if the multiplication of "a" and "b" will
+ * overflow. The types of "a" and "b" must match and must be unsigned.
+ * Note that this macro evaluates "a" twice!
+ */
+#define unsigned_mult_overflows(a, b) \
+    ((a) && (b) > maximum_unsigned_value_of_type(a) / (a))
+
 #ifdef __GNUC__
 #define TYPEOF(x) (__typeof__(x))
 #else
@@ -526,6 +534,33 @@ extern void release_pack_memory(size_t);
 typedef void (*try_to_free_t)(size_t);
 extern try_to_free_t set_try_to_free_routine(try_to_free_t);
 
+static inline size_t st_add(size_t a, size_t b)
+{
+	if (unsigned_add_overflows(a, b))
+		die("size_t overflow: %"PRIuMAX" + %"PRIuMAX,
+		    (uintmax_t)a, (uintmax_t)b);
+	return a + b;
+}
+#define st_add3(a,b,c)   st_add((a),st_add((b),(c)))
+#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))
+
+static inline size_t st_mult(size_t a, size_t b)
+{
+	if (unsigned_mult_overflows(a, b))
+		die("size_t overflow: %"PRIuMAX" * %"PRIuMAX,
+		    (uintmax_t)a, (uintmax_t)b);
+	return a * b;
+}
+
+static inline size_t st_sub(size_t a, size_t b)
+{
+	if (a < b)
+		die("size_t underflow: %"PRIuMAX" - %"PRIuMAX,
+		    (uintmax_t)a, (uintmax_t)b);
+	return a - b;
+}
+
+
 extern char *xstrdup(const char *str);
 extern void *xmalloc(size_t size);
 extern void *xmallocz(size_t size);
diff --git a/revision.c b/revision.c
index f40ccf1..b897ca6 100644
--- a/revision.c
+++ b/revision.c
@@ -24,16 +24,21 @@ char *path_name(const struct name_path *path, const char *name)
 {
 	const struct name_path *p;
 	char *n, *m;
-	int nlen = strlen(name);
-	int len = nlen + 1;
+	size_t nlen = strlen(name);
+	size_t len = st_add(nlen, 1);
+
+	if(len >= INT_MAX)
+		die("path_name(): path is too long.");
 
 	for (p = path; p; p = p->up) {
 		if (p->elem_len)
 			len += p->elem_len + 1;
+			if(len >= INT_MAX)
+				die("path_name(): path is too long.");
 	}
 	n = xmalloc(len);
 	m = n + len - (nlen + 1);
-	strcpy(m, name);
+	memcpy(m, name, nlen + 1);
 	for (p = path; p; p = p->up) {
 		if (p->elem_len) {
 			m -= p->elem_len + 1;
-- 
2.4.3