Commit ec3b4d35f636c26d3c9b5703c3b7f87683800af8

Edward Thomson 2015-02-11T11:20:05

Use `size_t` to hold size of arrays Use `size_t` to hold the size of arrays to ease overflow checking, lest we check for overflow of a `size_t` then promptly truncate by packing the length into a smaller type.

diff --git a/src/array.h b/src/array.h
index 0d07953..7c4dbdb 100644
--- a/src/array.h
+++ b/src/array.h
@@ -23,7 +23,7 @@
  *
  *     typedef git_array_t(my_struct) my_struct_array_t;
  */
-#define git_array_t(type) struct { type *ptr; uint32_t size, asize; }
+#define git_array_t(type) struct { type *ptr; size_t size, asize; }
 
 #define GIT_ARRAY_INIT { NULL, 0, 0 }
 
@@ -45,7 +45,7 @@ typedef git_array_t(char) git_array_generic_t;
 GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
 {
 	volatile git_array_generic_t *a = _a;
-	uint32_t new_size;
+	size_t new_size;
 	char *new_array;
 
 	if (a->size < 8) {
diff --git a/src/filebuf.c b/src/filebuf.c
index 1a91575..94f2bec 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -408,8 +408,8 @@ int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len)
 int git_filebuf_printf(git_filebuf *file, const char *format, ...)
 {
 	va_list arglist;
-	size_t space_left;
-	int len, res;
+	size_t space_left, len;
+	int written, res;
 	char *tmp_buffer;
 
 	ENSURE_BUF_OK(file);
@@ -418,15 +418,16 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...)
 
 	do {
 		va_start(arglist, format);
-		len = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist);
+		written = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist);
 		va_end(arglist);
 
-		if (len < 0) {
+		if (written < 0) {
 			file->last_error = BUFERR_MEM;
 			return -1;
 		}
 
-		if ((size_t)len + 1 <= space_left) {
+		len = written;
+		if (len + 1 <= space_left) {
 			file->buf_pos += len;
 			return 0;
 		}
@@ -436,7 +437,7 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...)
 
 		space_left = file->buf_size - file->buf_pos;
 
-	} while ((size_t)len + 1 <= space_left);
+	} while (len + 1 <= space_left);
 
 	if (GIT_ALLOC_OVERFLOW_ADD(len, 1) ||
 		!(tmp_buffer = git__malloc(len + 1))) {
diff --git a/src/pack-objects.c b/src/pack-objects.c
index 2880770..9b56234 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -190,6 +190,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
 {
 	git_pobject *po;
 	khiter_t pos;
+	size_t newsize;
 	int ret;
 
 	assert(pb && oid);
@@ -203,7 +204,14 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
 	if (pb->nr_objects >= pb->nr_alloc) {
 		GITERR_CHECK_ALLOC_ADD(pb->nr_alloc, 1024);
 		GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_alloc + 1024, 3 / 2);
-		pb->nr_alloc = (pb->nr_alloc + 1024) * 3 / 2;
+		newsize = (pb->nr_alloc + 1024) * 3 / 2;
+
+		if (!git__is_uint32(newsize)) {
+			giterr_set(GITERR_NOMEMORY, "Packfile too large to fit in memory.");
+			return -1;
+		}
+
+		pb->nr_alloc = (uint32_t)newsize;
 
 		pb->object_list = git__reallocarray(pb->object_list,
 			pb->nr_alloc, sizeof(*po));
diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c
index ad81ad1..11c6215 100644
--- a/src/transports/smart_pkt.c
+++ b/src/transports/smart_pkt.c
@@ -484,7 +484,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
 {
 	git_buf str = GIT_BUF_INIT;
 	char oid[GIT_OID_HEXSZ +1] = {0};
-	unsigned int len;
+	size_t len;
 
 	/* Prefer multi_ack_detailed */
 	if (caps->multi_ack_detailed)
@@ -510,12 +510,19 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
 	if (git_buf_oom(&str))
 		return -1;
 
-	len = (unsigned int)
-		(strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ +
-		 git_buf_len(&str) + 1 /* LF */);
+	len = strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ +
+		 git_buf_len(&str) + 1 /* LF */;
+
+	if (len > 0xffff) {
+		giterr_set(GITERR_NET,
+			"Tried to produce packet with invalid length %d", len);
+		return -1;
+	}
+
 	git_buf_grow_by(buf, len);
 	git_oid_fmt(oid, &head->oid);
-	git_buf_printf(buf, "%04xwant %s %s\n", len, oid, git_buf_cstr(&str));
+	git_buf_printf(buf,
+		"%04xwant %s %s\n", (unsigned int)len, oid, git_buf_cstr(&str));
 	git_buf_free(&str);
 
 	return git_buf_oom(buf);