Commit Diff


commit - dfb54902d34a7b74997a77674e6f8200141ed154
commit + 5b7e13a71fb6ddb69c2a98e5c8d5192d8805519b
blob - 4927b6057d86838ccd49bf408dff0712446eec31
blob + 86c785de07fb2604fc83ef040c4eef616c0598ad
--- include/got_error.h
+++ include/got_error.h
@@ -45,6 +45,7 @@
 #define GOT_ERR_WORKTREE_BUSY	29
 #define GOT_ERR_DIR_OBSTRUCTED	30
 #define GOT_ERR_FILE_OBSTRUCTED	31
+#define GOT_ERR_RECURSION	32
 
 static const struct got_error {
 	int code;
@@ -78,6 +79,7 @@ static const struct got_error {
 	{ GOT_ERR_WORKTREE_META,"bad worktree meta data" },
 	{ GOT_ERR_WORKTREE_VERS,"unsupported worktree format version" },
 	{ GOT_ERR_WORKTREE_BUSY,"worktree already locked" },
+	{ GOT_ERR_RECURSION,	"recursion limit reached" },
 };
 
 /*
blob - d7b25da90c43d78a330740ca5661a4a9e502595c
blob + 710d4edf7f4242a2bde28dbcbfcbdf99c9774b31
--- lib/pack.c
+++ lib/pack.c
@@ -55,6 +55,8 @@
 #define GOT_PACKIDX_NAMELEN	(strlen(GOT_PACK_PREFIX) + \
 				SHA1_DIGEST_STRING_LENGTH - 1 + \
 				strlen(GOT_PACKIDX_SUFFIX))
+
+#define GOT_DELTA_CHAIN_RECURSION_MAX	100
 
 #ifndef MIN
 #define	MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
@@ -734,7 +736,7 @@ parse_offset_delta(off_t *base_offset, FILE *packfile,
 
 static const struct got_error *
 resolve_delta_chain(struct got_delta_chain *, struct got_repository *,
-    FILE *, const char *, off_t, size_t, int, size_t);
+    FILE *, const char *, off_t, size_t, int, size_t, unsigned int);
 
 static const struct got_error *
 add_delta(struct got_delta_chain *deltas, const char *path_packfile,
@@ -757,7 +759,8 @@ add_delta(struct got_delta_chain *deltas, const char *
 static const struct got_error *
 resolve_offset_delta(struct got_delta_chain *deltas,
     struct got_repository *repo, FILE *packfile, const char *path_packfile,
-    off_t delta_offset,size_t tslen, int delta_type, size_t delta_size)
+    off_t delta_offset,size_t tslen, int delta_type, size_t delta_size,
+    unsigned int recursion)
 
 {
 	const struct got_error *err;
@@ -796,13 +799,13 @@ resolve_offset_delta(struct got_delta_chain *deltas,
 		return err;
 
 	return resolve_delta_chain(deltas, repo, packfile, path_packfile,
-	    base_offset, base_tslen, base_type, base_size);
+	    base_offset, base_tslen, base_type, base_size, recursion - 1);
 }
 
 static const struct got_error *
 resolve_ref_delta(struct got_delta_chain *deltas, struct got_repository *repo,
     FILE *packfile, const char *path_packfile, off_t delta_offset,
-    size_t tslen, int delta_type, size_t delta_size)
+    size_t tslen, int delta_type, size_t delta_size, unsigned int recursion)
 {
 	const struct got_error *err;
 	struct got_object_id id;
@@ -868,7 +871,7 @@ resolve_ref_delta(struct got_delta_chain *deltas, stru
 
 	err = resolve_delta_chain(deltas, repo, base_pack->packfile,
 	    path_base_packfile, base_offset, base_tslen, base_type,
-	    base_size);
+	    base_size, recursion - 1);
 done:
 	free(path_base_packfile);
 	return err;
@@ -877,10 +880,13 @@ done:
 static const struct got_error *
 resolve_delta_chain(struct got_delta_chain *deltas, struct got_repository *repo,
     FILE *packfile, const char *path_packfile, off_t delta_offset, size_t tslen,
-    int delta_type, size_t delta_size)
+    int delta_type, size_t delta_size, unsigned int recursion)
 {
 	const struct got_error *err = NULL;
 
+	if (--recursion == 0)
+		return got_error(GOT_ERR_RECURSION);
+
 	switch (delta_type) {
 	case GOT_OBJ_TYPE_COMMIT:
 	case GOT_OBJ_TYPE_TREE:
@@ -893,12 +899,12 @@ resolve_delta_chain(struct got_delta_chain *deltas, st
 	case GOT_OBJ_TYPE_OFFSET_DELTA:
 		err = resolve_offset_delta(deltas, repo, packfile,
 		    path_packfile, delta_offset, tslen, delta_type,
-		    delta_size);
+		    delta_size, recursion - 1);
 		break;
 	case GOT_OBJ_TYPE_REF_DELTA:
 		err = resolve_ref_delta(deltas, repo, packfile,
 		    path_packfile, delta_offset, tslen, delta_type,
-		    delta_size);
+		    delta_size, recursion - 1);
 		break;
 	default:
 		return got_error(GOT_ERR_OBJ_TYPE);
@@ -937,7 +943,8 @@ open_delta_object(struct got_object **obj, struct got_
 	(*obj)->flags |= GOT_OBJ_FLAG_DELTIFIED;
 
 	err = resolve_delta_chain(&(*obj)->deltas, repo, packfile,
-	    path_packfile, offset, tslen, delta_type, delta_size);
+	    path_packfile, offset, tslen, delta_type, delta_size,
+	    GOT_DELTA_CHAIN_RECURSION_MAX);
 	if (err)
 		goto done;