put a limit on delta chain recursion
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
diff --git a/include/got_error.h b/include/got_error.h
index 4927b60..86c785d 100644
--- a/include/got_error.h
+++ b/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" },
};
/*
diff --git a/lib/pack.c b/lib/pack.c
index d7b25da..710d4ed 100644
--- a/lib/pack.c
+++ b/lib/pack.c
@@ -56,6 +56,8 @@
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))
#endif
@@ -734,7 +736,7 @@ parse_offset_delta(off_t *base_offset, FILE *packfile, off_t offset)
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 *path_packfile,
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, struct got_repository *repo,
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, struct got_repository *repo,
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_repository *repo,
(*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;