Commit efe3f37d5fa3714263aca759126fd2e0a8a16370

Nelson Elhage 2018-07-12T04:20:15

Add a git_libgit2_opts option to set the max indexer object count

diff --git a/include/git2/common.h b/include/git2/common.h
index 8c93474..e5fff06 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -195,7 +195,9 @@ typedef enum {
 	GIT_OPT_SET_WINDOWS_SHAREMODE,
 	GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION,
 	GIT_OPT_SET_ALLOCATOR,
-	GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY
+	GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY,
+	GIT_OPT_GET_INDEXER_MAX_OBJECTS,
+	GIT_OPT_SET_INDEXER_MAX_OBJECTS
 } git_libgit2_opt_t;
 
 /**
@@ -372,6 +374,18 @@ typedef enum {
  *		> fail.  (Using the FORCE flag to checkout will still overwrite
  *		> these changes.)
  *
+ *	 opts(GIT_OPT_GET_INDEXER_MAX_OBJECTS, size_t *out)
+ *
+ *		> Get the maximum number of objects libgit2 will allow in a pack
+ *		> file when downloading a pack file from a remote. This can be
+ *		> used to limit maximum memory usage when fetching from an untrusted
+ *		> remote.
+ *
+ *	 opts(GIT_OPT_SET_INDEXER_MAX_OBJECTS, size_t objects)
+ *
+ *		> Set the maximum number of objects libgit2 will allow in a pack
+ *		> file when downloading a pack file from a remote.
+ *
  * @param option Option key
  * @param ... value to set the option
  * @return 0 on success, <0 on failure
diff --git a/src/indexer.c b/src/indexer.c
index 9cb0cc1..54d55dc 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -22,6 +22,8 @@
 
 extern git_mutex git__mwindow_mutex;
 
+size_t git_indexer__max_objects = (1ul << 32);
+
 #define UINT31_MAX (0x7FFFFFFF)
 
 struct entry {
@@ -557,17 +559,12 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran
 		idx->nr_objects = ntohl(hdr->hdr_entries);
 		idx->off = sizeof(struct git_pack_header);
 
-		/* for now, limit to 2^32 objects */
-		assert(idx->nr_objects == (size_t)((unsigned int)idx->nr_objects));
-		if (idx->nr_objects == (size_t)((unsigned int)idx->nr_objects))
+		if (idx->nr_objects <= git_indexer__max_objects) {
 			total_objects = (unsigned int)idx->nr_objects;
-		else
-			total_objects = UINT_MAX;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-		if (total_objects > 4096) {
-			total_objects = 4096;
+		} else {
+			giterr_set(GITERR_INDEXER, "too many objects");
+			return -1;
 		}
-#endif
 
 		idx->pack->idx_cache = git_oidmap_alloc();
 		GITERR_CHECK_ALLOC(idx->pack->idx_cache);
diff --git a/src/settings.c b/src/settings.c
index ba2f715..cac398d 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -56,6 +56,7 @@ int git_libgit2_features(void)
 /* Declarations for tuneable settings */
 extern size_t git_mwindow__window_size;
 extern size_t git_mwindow__mapped_limit;
+extern size_t git_indexer__max_objects;
 
 static int config_level_to_sysdir(int config_level)
 {
@@ -270,6 +271,14 @@ int git_libgit2_opts(int key, ...)
 		git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0);
 		break;
 
+	case GIT_OPT_SET_INDEXER_MAX_OBJECTS:
+		git_indexer__max_objects = va_arg(ap, size_t);
+		break;
+
+	case GIT_OPT_GET_INDEXER_MAX_OBJECTS:
+		*(va_arg(ap, size_t *)) = git_indexer__max_objects;
+		break;
+
 	default:
 		giterr_set(GITERR_INVALID, "invalid option key");
 		error = -1;
@@ -279,4 +288,3 @@ int git_libgit2_opts(int key, ...)
 
 	return error;
 }
-