Skip to content

Commit fb583dc

Browse files
gitsterdscho
authored andcommitted
Merge branch 'ps/upload-pack-oom-protection'
A broken or malicious "git fetch" can say that it has the same object for many many times, and the upload-pack serving it can exhaust memory storing them redundantly, which has been corrected. * ps/upload-pack-oom-protection: upload-pack: don't ACK non-commits repeatedly in protocol v2 t5530: modernize tests
2 parents 8032b78 + 88a2dc6 commit fb583dc

File tree

2 files changed

+51
-36
lines changed

2 files changed

+51
-36
lines changed

t/t5530-upload-pack-error.sh

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ test_description='errors in upload-pack'
44

55
. ./test-lib.sh
66

7-
D=$(pwd)
8-
97
corrupt_repo () {
108
object_sha1=$(git rev-parse "$1") &&
119
ob=$(expr "$object_sha1" : "\(..\)") &&
@@ -21,11 +19,7 @@ test_expect_success 'setup and corrupt repository' '
2119
test_tick &&
2220
echo changed >file &&
2321
git commit -a -m changed &&
24-
corrupt_repo HEAD:file
25-
26-
'
27-
28-
test_expect_success 'fsck fails' '
22+
corrupt_repo HEAD:file &&
2923
test_must_fail git fsck
3024
'
3125

@@ -40,17 +34,12 @@ test_expect_success 'upload-pack fails due to error in pack-objects packing' '
4034
'
4135

4236
test_expect_success 'corrupt repo differently' '
43-
4437
git hash-object -w file &&
45-
corrupt_repo HEAD^^{tree}
46-
47-
'
48-
49-
test_expect_success 'fsck fails' '
38+
corrupt_repo HEAD^^{tree} &&
5039
test_must_fail git fsck
5140
'
52-
test_expect_success 'upload-pack fails due to error in rev-list' '
5341

42+
test_expect_success 'upload-pack fails due to error in rev-list' '
5443
printf "%04xwant %s\n%04xshallow %s00000009done\n0000" \
5544
$(($hexsz + 10)) $(git rev-parse HEAD) \
5645
$(($hexsz + 12)) $(git rev-parse HEAD^) >input &&
@@ -59,7 +48,6 @@ test_expect_success 'upload-pack fails due to error in rev-list' '
5948
'
6049

6150
test_expect_success 'upload-pack fails due to bad want (no object)' '
62-
6351
printf "%04xwant %s multi_ack_detailed\n00000009done\n0000" \
6452
$(($hexsz + 29)) $(test_oid deadbeef) >input &&
6553
test_must_fail git upload-pack . <input >output 2>output.err &&
@@ -69,7 +57,6 @@ test_expect_success 'upload-pack fails due to bad want (no object)' '
6957
'
7058

7159
test_expect_success 'upload-pack fails due to bad want (not tip)' '
72-
7360
oid=$(echo an object we have | git hash-object -w --stdin) &&
7461
printf "%04xwant %s multi_ack_detailed\n00000009done\n0000" \
7562
$(($hexsz + 29)) "$oid" >input &&
@@ -80,7 +67,6 @@ test_expect_success 'upload-pack fails due to bad want (not tip)' '
8067
'
8168

8269
test_expect_success 'upload-pack fails due to error in pack-objects enumeration' '
83-
8470
printf "%04xwant %s\n00000009done\n0000" \
8571
$((hexsz + 10)) $(git rev-parse HEAD) >input &&
8672
test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
@@ -105,18 +91,48 @@ test_expect_success 'upload-pack tolerates EOF just after stateless client wants
10591
test_cmp expect actual
10692
'
10793

108-
test_expect_success 'create empty repository' '
109-
110-
mkdir foo &&
111-
cd foo &&
112-
git init
113-
114-
'
115-
11694
test_expect_success 'fetch fails' '
95+
git init foo &&
96+
test_must_fail git -C foo fetch .. main
97+
'
11798

118-
test_must_fail git fetch .. main
99+
test_expect_success 'upload-pack ACKs repeated non-commit objects repeatedly (protocol v0)' '
100+
commit_id=$(git rev-parse HEAD) &&
101+
tree_id=$(git rev-parse HEAD^{tree}) &&
102+
test-tool pkt-line pack >request <<-EOF &&
103+
want $commit_id
104+
0000
105+
have $tree_id
106+
have $tree_id
107+
0000
108+
EOF
109+
git upload-pack --stateless-rpc . <request >actual &&
110+
depacketize <actual >actual.raw &&
111+
grep ^ACK actual.raw >actual.acks &&
112+
cat >expect <<-EOF &&
113+
ACK $tree_id
114+
ACK $tree_id
115+
EOF
116+
test_cmp expect actual.acks
117+
'
119118

119+
test_expect_success 'upload-pack ACKs repeated non-commit objects once only (protocol v2)' '
120+
commit_id=$(git rev-parse HEAD) &&
121+
tree_id=$(git rev-parse HEAD^{tree}) &&
122+
test-tool pkt-line pack >request <<-EOF &&
123+
command=fetch
124+
object-format=$(test_oid algo)
125+
0001
126+
want $commit_id
127+
have $tree_id
128+
have $tree_id
129+
0000
130+
EOF
131+
GIT_PROTOCOL=version=2 git upload-pack . <request >actual &&
132+
depacketize <actual >actual.raw &&
133+
grep ^ACK actual.raw >actual.acks &&
134+
echo "ACK $tree_id" >expect &&
135+
test_cmp expect actual.acks
120136
'
121137

122138
test_done

upload-pack.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -476,32 +476,31 @@ static void create_pack_file(struct upload_pack_data *pack_data,
476476

477477
static int do_got_oid(struct upload_pack_data *data, const struct object_id *oid)
478478
{
479-
int we_knew_they_have = 0;
480479
struct object *o = parse_object_with_flags(the_repository, oid,
481480
PARSE_OBJECT_SKIP_HASH_CHECK |
482481
PARSE_OBJECT_DISCARD_TREE);
483482

484483
if (!o)
485484
die("oops (%s)", oid_to_hex(oid));
485+
486486
if (o->type == OBJ_COMMIT) {
487487
struct commit_list *parents;
488488
struct commit *commit = (struct commit *)o;
489-
if (o->flags & THEY_HAVE)
490-
we_knew_they_have = 1;
491-
else
492-
o->flags |= THEY_HAVE;
489+
493490
if (!data->oldest_have || (commit->date < data->oldest_have))
494491
data->oldest_have = commit->date;
495492
for (parents = commit->parents;
496493
parents;
497494
parents = parents->next)
498495
parents->item->object.flags |= THEY_HAVE;
499496
}
500-
if (!we_knew_they_have) {
501-
add_object_array(o, NULL, &data->have_obj);
502-
return 1;
503-
}
504-
return 0;
497+
498+
if (o->flags & THEY_HAVE)
499+
return 0;
500+
o->flags |= THEY_HAVE;
501+
502+
add_object_array(o, NULL, &data->have_obj);
503+
return 1;
505504
}
506505

507506
static int got_oid(struct upload_pack_data *data,

0 commit comments

Comments
 (0)