Skip to content

Commit c39fc06

Browse files
ttaylorrgitster
authored andcommitted
fmt-merge-msg: prevent use-after-free with signed tags
When merging a signed tag, fmt_merge_msg_sigs() is responsible for populating the body of the merge message with the names of the signed tags, their signatures, and the validity of those signatures. In 0276943 (ssh signing: use sigc struct to pass payload, 2021-12-09), check_signature() was taught to pass the object payload via the sigc struct instead of passing the payload buffer separately. In effect, 0276943 causes buf, and sigc.payload to point at the same region in memory. This causes a problem for fmt_tag_signature(), which wants to read from this location, since it is freed beforehand by signature_check_clear() (which frees it via sigc's `payload` member). That makes the subsequent use in fmt_tag_signature() a use-after-free. As a result, merge messages did not contain the body of any signed tags. Luckily, they tend not to contain garbage, either, since the result of strstr()-ing the object buffer in fmt_tag_signature() is guarded: const char *tag_body = strstr(buf, "\n\n"); if (tag_body) { tag_body += 2; strbuf_add(tagbuf, tag_body, buf + len - tag_body); } Unfortunately, the tests in t6200 did not catch this at the time because they do not search for the body of signed tags in fmt-merge-msg's output. Resolve this by waiting to call signature_check_clear() until after its contents can be safely discarded. Harden ourselves against any future regressions in this area by making sure we can find signed tag messages in the output of fmt-merge-msg, too. Reported-by: Linus Torvalds <[email protected]> Signed-off-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 50992f9 commit c39fc06

File tree

2 files changed

+9
-1
lines changed

2 files changed

+9
-1
lines changed

fmt-merge-msg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,6 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
541541
else
542542
strbuf_addstr(&sig, sigc.output);
543543
}
544-
signature_check_clear(&sigc);
545544

546545
if (!tag_number++) {
547546
fmt_tag_signature(&tagbuf, &sig, buf, len);
@@ -565,6 +564,7 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
565564
}
566565
strbuf_release(&payload);
567566
strbuf_release(&sig);
567+
signature_check_clear(&sigc);
568568
next:
569569
free(origbuf);
570570
}

t/t6200-fmt-merge-msg.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ test_expect_success GPG 'message for merging local tag signed by good key' '
126126
git fetch . signed-good-tag &&
127127
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
128128
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
129+
grep "^signed-tag-msg" actual &&
129130
grep "^# gpg: Signature made" actual &&
130131
grep "^# gpg: Good signature from" actual
131132
'
@@ -135,6 +136,7 @@ test_expect_success GPG 'message for merging local tag signed by unknown key' '
135136
git fetch . signed-good-tag &&
136137
GNUPGHOME=. git fmt-merge-msg <.git/FETCH_HEAD >actual &&
137138
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
139+
grep "^signed-tag-msg" actual &&
138140
grep "^# gpg: Signature made" actual &&
139141
grep -E "^# gpg: Can${apos}t check signature: (public key not found|No public key)" actual
140142
'
@@ -145,6 +147,7 @@ test_expect_success GPGSSH 'message for merging local tag signed by good ssh key
145147
git fetch . signed-good-ssh-tag &&
146148
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
147149
grep "^Merge tag ${apos}signed-good-ssh-tag${apos}" actual &&
150+
grep "^signed-ssh-tag-msg" actual &&
148151
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
149152
! grep "${GPGSSH_BAD_SIGNATURE}" actual
150153
'
@@ -155,6 +158,7 @@ test_expect_success GPGSSH 'message for merging local tag signed by unknown ssh
155158
git fetch . signed-untrusted-ssh-tag &&
156159
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
157160
grep "^Merge tag ${apos}signed-untrusted-ssh-tag${apos}" actual &&
161+
grep "^signed-ssh-tag-msg-untrusted" actual &&
158162
grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual &&
159163
! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
160164
grep "${GPGSSH_KEY_NOT_TRUSTED}" actual
@@ -166,6 +170,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag sign
166170
git fetch . expired-signed &&
167171
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
168172
grep "^Merge tag ${apos}expired-signed${apos}" actual &&
173+
grep "^expired-signed" actual &&
169174
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
170175
'
171176

@@ -175,6 +180,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag sign
175180
git fetch . notyetvalid-signed &&
176181
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
177182
grep "^Merge tag ${apos}notyetvalid-signed${apos}" actual &&
183+
grep "^notyetvalid-signed" actual &&
178184
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
179185
'
180186

@@ -184,6 +190,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag sign
184190
git fetch . timeboxedvalid-signed &&
185191
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
186192
grep "^Merge tag ${apos}timeboxedvalid-signed${apos}" actual &&
193+
grep "^timeboxedvalid-signed" actual &&
187194
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
188195
! grep "${GPGSSH_BAD_SIGNATURE}" actual
189196
'
@@ -194,6 +201,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag sign
194201
git fetch . timeboxedinvalid-signed &&
195202
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
196203
grep "^Merge tag ${apos}timeboxedinvalid-signed${apos}" actual &&
204+
grep "^timeboxedinvalid-signed" actual &&
197205
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
198206
'
199207

0 commit comments

Comments
 (0)