Skip to content

Commit 8977e32

Browse files
pks-tgitster
authored andcommitted
ref-filter: detect broken tags when dereferencing them
Users can ask git-for-each-ref(1) to peel tags and return information of the tagged object by adding an asterisk to the format, like for example "%(*$objectname)". If so, git-for-each-ref(1) peels that object to the first non-tag object and then returns its values. As mentioned in preceding commits, it can happen that the tagged object type and the claimed object type differ, effectively resulting in a corrupt tag. git-for-each-ref(1) would notice this mismatch, print an error and then bail out when trying to peel the tag. But we only notice this corruption in some very specific edge cases! While we have a test in "t/for-each-ref-tests.sh" that verifies the above scenario, this test is specifically crafted to detect the issue at hand. Namely, we create two tags: - One tag points to a specific object with the correct type. - The other tag points to the *same* object with a different type. The fact that both tags point to the same object is important here: `peel_object()` wouldn't notice the corruption if the tagged objects were different. The root cause is that `peel_object()` calls `lookup_${type}()` eventually, where the type is the same type declared in the tag object. Consequently, when we have two tags pointing to the same object but with different declared types we'll call two different lookup functions. The first lookup will store the object with an unverified type A, whereas the second lookup will try to look up the object with a different unverified type B. And it is only now that we notice the discrepancy in object types, even though type A could've already been the wrong type. Fix the issue by verifying the object type in `populate_value()`. With this change we'll also notice type mismatches when only dereferencing a tag once. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7e42fac commit 8977e32

File tree

2 files changed

+5
-2
lines changed

2 files changed

+5
-2
lines changed

ref-filter.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2581,7 +2581,8 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
25812581
if (need_tagged) {
25822582
if (!is_null_oid(&ref->peeled_oid)) {
25832583
oidcpy(&oi_deref.oid, &ref->peeled_oid);
2584-
} else if (!peel_object(the_repository, &oi.oid, &oi_deref.oid, 0)) {
2584+
} else if (!peel_object(the_repository, &oi.oid, &oi_deref.oid,
2585+
PEEL_OBJECT_VERIFY_OBJECT_TYPE)) {
25852586
/* We managed to peel the object ourselves. */
25862587
} else {
25872588
die("bad tag");

t/for-each-ref-tests.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,7 +1809,9 @@ test_expect_success "${git_for_each_ref} reports broken tags" '
18091809
bad=$(git hash-object -w -t tag bad) &&
18101810
git update-ref refs/tags/broken-tag-bad $bad &&
18111811
test_must_fail ${git_for_each_ref} --format="%(*objectname)" \
1812-
refs/tags/broken-tag-*
1812+
refs/tags/broken-tag-* &&
1813+
test_must_fail ${git_for_each_ref} --format="%(*objectname)" \
1814+
refs/tags/broken-tag-bad
18131815
'
18141816

18151817
test_expect_success 'set up tag with signature and no blank lines' '

0 commit comments

Comments
 (0)