From: Han Xin <hanxin.hx@xxxxxxxxxxxxxxx> In addition to using 'receive.maxInputSize' to limit the overall size of the received packfile, a new config variable 'receive.maxInputObjectSize' is added to limit the push of a single object larger than this threshold. Signed-off-by: Han Xin <hanxin.hx@xxxxxxxxxxxxxxx> --- Documentation/config/receive.txt | 6 ++++++ builtin/index-pack.c | 5 +++++ builtin/receive-pack.c | 12 ++++++++++++ builtin/unpack-objects.c | 8 ++++++++ t/t5546-receive-limits.sh | 25 +++++++++++++++++++++++++ 5 files changed, 56 insertions(+) diff --git a/Documentation/config/receive.txt b/Documentation/config/receive.txt index 85d5b5a3d2..4823ead8e4 100644 --- a/Documentation/config/receive.txt +++ b/Documentation/config/receive.txt @@ -74,6 +74,12 @@ receive.maxInputSize:: accepting the pack file. If not set or set to 0, then the size is unlimited. +receive.maxInputObjectSize:: + If one of the objects in the incoming pack stream is larger than + this limit, then git-receive-pack will error out, instead of + accepting the pack file. If not set or set to 0, then the size + is unlimited. + receive.denyDeletes:: If set to true, git-receive-pack will deny a ref update that deletes the ref. Use this to prevent such a ref deletion via a push. diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 8336466865..0e62b356c6 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -133,6 +133,7 @@ static unsigned char input_buffer[4096]; static unsigned int input_offset, input_len; static off_t consumed_bytes; static off_t max_input_size; +static off_t max_input_object_size; static unsigned deepest_delta; static git_hash_ctx input_ctx; static uint32_t input_crc32; @@ -519,6 +520,8 @@ static void *unpack_raw_entry(struct object_entry *obj, shift += 7; } obj->size = size; + if (max_input_object_size && size > max_input_object_size) + die(_("object exceeds maximum allowed size ")); switch (obj->type) { case OBJ_REF_DELTA: @@ -1825,6 +1828,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) die(_("bad %s"), arg); } else if (skip_prefix(arg, "--max-input-size=", &arg)) { max_input_size = strtoumax(arg, NULL, 10); + } else if (skip_prefix(arg, "--max-input-object-size=", &arg)) { + max_input_object_size = strtoumax(arg, NULL, 10); } else if (skip_prefix(arg, "--object-format=", &arg)) { hash_algo = hash_algo_by_name(arg); if (hash_algo == GIT_HASH_UNKNOWN) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 2d1f97e1ca..82ff0c61ff 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -57,6 +57,7 @@ static int advertise_push_options; static int advertise_sid; static int unpack_limit = 100; static off_t max_input_size; +static off_t max_input_object_size; static int report_status; static int report_status_v2; static int use_sideband; @@ -242,6 +243,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb) return 0; } + if (strcmp(var, "receive.maxinputobjectsize") == 0) { + max_input_object_size = git_config_int64(var, value); + return 0; + } + if (strcmp(var, "receive.procreceiverefs") == 0) { if (!value) return config_error_nonbool(var); @@ -2237,6 +2243,9 @@ static const char *unpack(int err_fd, struct shallow_info *si) if (max_input_size) strvec_pushf(&child.args, "--max-input-size=%"PRIuMAX, (uintmax_t)max_input_size); + if (max_input_object_size) + strvec_pushf(&child.args, "--max-input-object-size=%"PRIuMAX, + (uintmax_t)max_input_object_size); child.no_stdout = 1; child.err = err_fd; child.git_cmd = 1; @@ -2268,6 +2277,9 @@ static const char *unpack(int err_fd, struct shallow_info *si) if (max_input_size) strvec_pushf(&child.args, "--max-input-size=%"PRIuMAX, (uintmax_t)max_input_size); + if (max_input_object_size) + strvec_pushf(&child.args, "--max-input-object-size=%"PRIuMAX, + (uintmax_t)max_input_object_size); child.out = -1; child.err = err_fd; child.git_cmd = 1; diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 4a9466295b..04d9fa918f 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -22,6 +22,7 @@ static unsigned char buffer[4096]; static unsigned int offset, len; static off_t consumed_bytes; static off_t max_input_size; +static off_t max_input_object_size; static git_hash_ctx ctx; static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT; static struct progress *progress; @@ -466,6 +467,9 @@ static void unpack_one(unsigned nr) shift += 7; } + if (max_input_object_size && size > max_input_object_size) + die(_("object exceeds maximum allowed size ")); + switch (type) { case OBJ_COMMIT: case OBJ_TREE: @@ -568,6 +572,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) max_input_size = strtoumax(arg, NULL, 10); continue; } + if (skip_prefix(arg, "--max-input-object-size=", &arg)) { + max_input_object_size = strtoumax(arg, NULL, 10); + continue; + } usage(unpack_usage); } diff --git a/t/t5546-receive-limits.sh b/t/t5546-receive-limits.sh index 0b0e987fdb..52c8f1f2e8 100755 --- a/t/t5546-receive-limits.sh +++ b/t/t5546-receive-limits.sh @@ -41,6 +41,31 @@ test_pack_input_limit () { git --git-dir=dest config receive.maxInputSize 0 && git push dest HEAD ' + + test_expect_success 'prepare destination repository (test for large object)' ' + rm -fr dest && + git --bare init dest + ' + + test_expect_success 'setting receive.maxInputObjectSize to 512 rejects push large object' ' + git -C dest config receive.maxInputObjectSize 512 && + test_must_fail git push dest HEAD + ' + + test_expect_success 'bumping limit to 2k allows push large object' ' + git -C dest config receive.maxInputObjectSize 2k && + git push dest HEAD + ' + + test_expect_success 'prepare destination repository (test for large object,again)' ' + rm -fr dest && + git --bare init dest + ' + + test_expect_success 'lifting the limit allows push' ' + git -C dest config receive.maxInputObjectSize 0 && + git push dest HEAD + ' } test_expect_success "create known-size (1024 bytes) commit" ' -- 2.33.0.1.g0542904d0a.dirty