From: Johan Herland <johan@herland.net>
To: Junio C Hamano <gitster@pobox.com>
Cc: Shawn Pearce <spearce@spearce.org>,
Johan Herland <johan@herland.net>,
git@vger.kernel.org
Subject: [PATCHv3 7/9] send-pack/receive-pack: Allow server to refuse pushes with too many objects
Date: Sun, 15 May 2011 23:37:18 +0200 [thread overview]
Message-ID: <1305495440-30836-8-git-send-email-johan@herland.net> (raw)
In-Reply-To: <1305495440-30836-1-git-send-email-johan@herland.net>
Add a new receive.objectCountLimit config variable which defines an upper
limit on the number of objects to accept in a single push.
This limit is advertised to clients, using the new "limit-object-count=<num>"
capability. The client side - aka. send-pack - parses this capability and
forwards it to pack-objects, using the recently added --max-object-count
option. pack-objects then checks the generated pack against the limit and
aborts the pack generation if the pack would have too many objects.
Additionally - for older clients that do not understand the capability - the
server aborts the transfer if the number of objects in the transferred pack
exceeds the limit. This is a suboptimal fallback solution, as it leaves the
client with a broken pipe, and likely a confused user.
Server administrators might want to use this config variable to prevent
unintended large pushes from entering the repo (typically a result of the
user not being aware of exactly what is being pushed, e.g. pushing a large
rewritten history). Note that this config variable is not intended to protect
against DoS attacks, since there are countless other ways to attempt to DoS a
server without violating this limit.
Traditionally, this kind of limit would be imposed by a pre-receive or update
hook, but both of those run _after_ the pack has been received and stored by
receive-pack, so they cannot prevent the pack from being stored on the server.
Documentation and tests are included.
Signed-off-by: Johan Herland <johan@herland.net>
---
Documentation/config.txt | 9 +++
Documentation/technical/protocol-capabilities.txt | 2 +
builtin/receive-pack.c | 13 ++++-
builtin/send-pack.c | 10 +++
send-pack.h | 1 +
t/t5400-send-pack.sh | 66 +++++++++++++++++++++
6 files changed, 100 insertions(+), 1 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 056e01f..fd6c130 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1599,6 +1599,15 @@ receive.unpackLimit::
especially on slow filesystems. If not set, the value of
`transfer.unpackLimit` is used instead.
+receive.objectCountLimit::
+ If the number of objects received in a push exceeds this limit,
+ then the entire push will be refused. This is meant to prevent
+ an unintended large push (typically a result of the user not
+ being aware of exactly what is being pushed, e.g. pushing a
+ large rewritten history) from entering the repo. If not set,
+ there is no upper limit on the number of objects transferred
+ in a single push.
+
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/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index 11849a3..aac66af 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -205,5 +205,7 @@ the server. If the check fails, the client must abort the upload, and
report the reason for the aborted push back to the user.
The following "limit-*" capabilites are recognized:
+ - limit-object-count=<num> (Maximum number of objects in a pack)
+
More "limit-*" capabilities may be added in the future. The client
is free to ignore any "limit-*" capabilities it does not understand.
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index c55989d..d919e17 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -28,6 +28,7 @@ static int receive_fsck_objects;
static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
+static unsigned long limit_object_count;
static int report_status;
static int use_sideband;
static int prefer_ofs_delta = 1;
@@ -73,6 +74,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
+ if (strcmp(var, "receive.objectcountlimit") == 0) {
+ limit_object_count = git_config_ulong(var, value);
+ return 0;
+ }
+
if (strcmp(var, "receive.fsckobjects") == 0) {
receive_fsck_objects = git_config_bool(var, value);
return 0;
@@ -112,6 +118,9 @@ static const char *capabilities()
int ret = snprintf(buf, sizeof(buf),
" report-status delete-refs side-band-64k%s",
prefer_ofs_delta ? " ofs-delta" : "");
+ if (limit_object_count > 0)
+ ret += snprintf(buf + ret, sizeof(buf) - ret,
+ " limit-object-count=%lu", limit_object_count);
assert(ret < sizeof(buf));
return buf;
}
@@ -656,7 +665,9 @@ static const char *unpack(void)
"--pack_header=%"PRIu32",%"PRIu32,
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
- if (ntohl(hdr.hdr_entries) < unpack_limit) {
+ if (limit_object_count > 0 && ntohl(hdr.hdr_entries) > limit_object_count)
+ return "received pack exceeds configured receive.objectCountLimit";
+ else if (ntohl(hdr.hdr_entries) < unpack_limit) {
int code, i = 0;
const char *unpacker[4];
unpacker[i++] = "unpack-objects";
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index f571917..4103116 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -49,9 +49,11 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
NULL,
NULL,
NULL,
+ NULL,
};
struct child_process po;
int i;
+ char buf[40];
i = 4;
if (args->use_thin_pack)
@@ -62,6 +64,11 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
argv[i++] = "-q";
if (args->progress)
argv[i++] = "--progress";
+ if (args->max_object_count > 0) {
+ snprintf(buf, sizeof(buf), "--max-object-count=%lu",
+ args->max_object_count);
+ argv[i++] = buf;
+ }
memset(&po, 0, sizeof(po));
po.argv = argv;
po.in = -1;
@@ -253,6 +260,7 @@ int send_pack(struct send_pack_args *args,
unsigned cmds_sent = 0;
int ret = 0;
struct async demux;
+ const char *p;
/* Does the other end support the reporting? */
if (server_supports("report-status"))
@@ -263,6 +271,8 @@ int send_pack(struct send_pack_args *args,
args->use_ofs_delta = 1;
if (server_supports("side-band-64k"))
use_sideband = 1;
+ if ((p = server_supports("limit-object-count=")))
+ args->max_object_count = strtoul(p + 19, NULL, 10);
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
diff --git a/send-pack.h b/send-pack.h
index 05d7ab1..eaacb20 100644
--- a/send-pack.h
+++ b/send-pack.h
@@ -12,6 +12,7 @@ struct send_pack_args {
use_ofs_delta:1,
dry_run:1,
stateless_rpc:1;
+ unsigned long max_object_count;
};
int send_pack(struct send_pack_args *args,
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 0eace37..f1f8f80 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -222,4 +222,70 @@ test_expect_success 'deny pushing to delete current branch' '
)
'
+echo "0000" > pkt-flush
+
+test_expect_success 'verify that limit-object-count capability is not advertised by default' '
+ rewound_push_setup &&
+ (
+ cd parent &&
+ test_might_fail git receive-pack . <../pkt-flush >output &&
+ test_must_fail grep -q "limit-object-count" output
+ )
+'
+
+test_expect_success 'verify that receive.objectCountLimit triggers limit-object-count capability' '
+ (
+ cd parent &&
+ git config receive.objectCountLimit 1 &&
+ test_might_fail git receive-pack . <../pkt-flush >output &&
+ grep -q "limit-object-count=1" output
+ )
+'
+
+test_expect_success 'deny pushing when receive.objectCountLimit is exceeded' '
+ (
+ cd child &&
+ git reset --hard origin/master &&
+ echo three > file && git commit -a -m three &&
+ test_must_fail git send-pack ../parent master 2>errs &&
+ grep -q "object count limit" errs
+ ) &&
+ parent_head=$(cd parent && git rev-parse --verify master) &&
+ child_head=$(cd child && git rev-parse --verify master) &&
+ test "$parent_head" != "$child_head"
+'
+
+test_expect_success 'repeated push failure proves that objects were not stored remotely' '
+ (
+ cd child &&
+ test_must_fail git send-pack ../parent master 2>errs &&
+ grep -q "object count limit" errs
+ ) &&
+ parent_head=$(cd parent && git rev-parse --verify master) &&
+ child_head=$(cd child && git rev-parse --verify master) &&
+ test "$parent_head" != "$child_head"
+'
+
+test_expect_success 'increase receive.objectCountLimit' '
+ (
+ cd parent &&
+ git config receive.objectCountLimit 10 &&
+ test_might_fail git receive-pack . <../pkt-flush >output &&
+ grep -q "limit-object-count=10" output
+ )
+'
+
+test_expect_success 'push is allowed when object limit is not exceeded' '
+ (
+ cd child &&
+ git send-pack ../parent master 2>errs &&
+ test_must_fail grep -q "object count limit" errs &&
+ # Also no error message from remote receive-pack
+ test_must_fail grep -q "receive\\.objectCountLimit" errs
+ ) &&
+ parent_head=$(cd parent && git rev-parse --verify master) &&
+ child_head=$(cd child && git rev-parse --verify master) &&
+ test "$parent_head" = "$child_head"
+'
+
test_done
--
1.7.5.rc1.3.g4d7b
next prev parent reply other threads:[~2011-05-15 21:38 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-05-13 16:54 [PATCH 2/2] receive-pack: Add receive.denyObjectLimit to refuse push with too many objects Johan Herland
2011-05-13 17:09 ` Junio C Hamano
2011-05-14 1:43 ` Johan Herland
2011-05-14 2:03 ` [PATCHv2 2/2] receive-pack: Add receive.objectCountLimit " Johan Herland
2011-05-14 2:30 ` Shawn Pearce
2011-05-14 13:17 ` Johan Herland
2011-05-14 22:17 ` Shawn Pearce
2011-05-15 17:42 ` Johan Herland
2011-05-15 21:37 ` [PATCHv3 0/9] Push limits Johan Herland
2011-05-15 21:37 ` [PATCHv3 1/9] Update technical docs to reflect side-band-64k capability in receive-pack Johan Herland
2011-05-15 21:37 ` [PATCHv3 2/9] send-pack: Attempt to retrieve remote status even if pack-objects fails Johan Herland
2011-05-16 4:07 ` Jeff King
2011-05-16 6:13 ` Jeff King
2011-05-16 6:39 ` Jeff King
2011-05-16 6:46 ` [PATCH 1/3] connect: treat generic proxy processes like ssh processes Jeff King
2011-05-16 19:57 ` Johannes Sixt
2011-05-16 23:12 ` Junio C Hamano
2011-05-17 5:54 ` Jeff King
2011-05-17 20:14 ` Johannes Sixt
2011-05-18 8:57 ` Jeff King
2011-05-16 6:52 ` [PATCH 2/3] connect: let callers know if connection is a socket Jeff King
2011-05-16 6:52 ` [PATCH 3/3] send-pack: avoid deadlock on git:// push with failed pack-objects Jeff King
2011-05-16 20:02 ` Johannes Sixt
2011-05-17 5:56 ` Jeff King
2011-05-18 20:24 ` [PATCH] Windows: add a wrapper for the shutdown() system call Johannes Sixt
2011-05-15 21:37 ` [PATCHv3 3/9] pack-objects: Allow --max-pack-size to be used together with --stdout Johan Herland
2011-05-15 22:06 ` Shawn Pearce
2011-05-16 1:39 ` Johan Herland
2011-05-16 6:12 ` Junio C Hamano
2011-05-16 9:27 ` Johan Herland
2011-05-15 21:37 ` [PATCHv3 4/9] pack-objects: Teach new option --max-object-count, similar to --max-pack-size Johan Herland
2011-05-15 22:07 ` Shawn Pearce
2011-05-15 22:31 ` Johan Herland
2011-05-15 23:48 ` Shawn Pearce
2011-05-16 6:25 ` Junio C Hamano
2011-05-16 9:49 ` Johan Herland
2011-05-15 21:37 ` [PATCHv3 5/9] pack-objects: Teach new option --max-commit-count, limiting #commits in pack Johan Herland
2011-05-15 21:37 ` [PATCHv3 6/9] receive-pack: Prepare for addition of the new 'limit-*' family of capabilities Johan Herland
2011-05-16 6:50 ` Junio C Hamano
2011-05-16 9:53 ` Johan Herland
2011-05-16 22:02 ` Sverre Rabbelier
2011-05-16 22:07 ` Junio C Hamano
2011-05-16 22:09 ` Sverre Rabbelier
2011-05-16 22:12 ` Junio C Hamano
2011-05-16 22:16 ` Sverre Rabbelier
2011-05-15 21:37 ` Johan Herland [this message]
2011-05-15 21:37 ` [PATCHv3 8/9] send-pack/receive-pack: Allow server to refuse pushing too large packs Johan Herland
2011-05-15 21:37 ` [PATCHv3 9/9] send-pack/receive-pack: Allow server to refuse pushes with too many commits Johan Herland
2011-05-15 21:52 ` [PATCHv3 0/9] Push limits Ævar Arnfjörð Bjarmason
2011-05-14 17:50 ` [PATCHv2 2/2] receive-pack: Add receive.objectCountLimit to refuse push with too many objects Junio C Hamano
2011-05-14 22:27 ` Shawn Pearce
2011-05-13 18:20 ` [PATCH 2/2] receive-pack: Add receive.denyObjectLimit " Johannes Sixt
2011-05-14 1:49 ` Johan Herland
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1305495440-30836-8-git-send-email-johan@herland.net \
--to=johan@herland.net \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=spearce@spearce.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).