Skip to contentSkip to conversation

http-push: trim trailing newline from remote symref

PATCH In review Jeff King 3 participants 6 messages Jun 15, 2016

lore
Share & tools
lore

Jeff King

author
#0 lore raw

PATCH 1/1 http-push: trim trailing newline from remote symref

When we fetch a symbolic ref file from the remote, we get the whole string "ref: refs/heads/master\n", recognize it by skipping past the "ref: ", and store the rest. We should chomp the trailing newline.

This bug was introduced in ae021d8 (use skip_prefix to avoid magic numbers, 2014-06-18), which did not notice that the length computation fed to xmemdupz was quietly tweaked by 1 to account for this.

We can solve it by explicitly trimming the newline, which is more obvious. Note that we use strbuf_rtrim here, which will actually cut off any trailing whitespace, not just a single newline. This is a good thing, though, as it makes our parsing more liberal (and spaces are not valid in refnames anyway).

---
This is a regression in v2.1.0.

It was causing t5540 to fail, but I realized I have been building with NO_EXPAT for a while, so I didn't notice. Frankly, I'm kind of surprised and disturbed that nobody noticed it before now. More evidence that we can kill off dumb http-push? I would have thought somebody else would have noticed the test failure, though.

I am embarrassed to have introduced the bug during a refactoring patch. But in my defense, the original code was quite subtle and horrible, and I think the end result at least is much obvious (and is a good point in favor of skip_prefix's existence!). The original came from eecc836 (Another memory overrun in http-push.c, 2007-03-01). Looking at that patch, I can't understand how the code before it ever worked in the first place.

 http-push.c | 3 +++
 1 file changed, 3 insertions(+)
http-push.c +3 -0
index 26dfa67..184d24a 100644
@@ -1578,6 +1578,9 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
 	if (buffer.len == 0)
 		return;
 
+	/* Cut off trailing newline. */
+	strbuf_rtrim(&buffer);
+
 	/* If it's a symref, set the refname; otherwise try for a sha1 */
 	if (skip_prefix(buffer.buf, "ref: ", &name)) {
 		*symref = xmemdupz(name, buffer.len - (name - buffer.buf));
Signature · 1 line
2.2.1.425.g441bb3c
author
#1 lore raw
Quoted 10 lines · Jeff King

When we fetch a symbolic ref file from the remote, we get the whole string "ref: refs/heads/master\n", recognize it by skipping past the "ref: ", and store the rest. We should chomp the trailing newline.

This bug was introduced in ae021d8 (use skip_prefix to avoid magic numbers, 2014-06-18), which did not notice that the length computation fed to xmemdupz was quietly tweaked by 1 to account for this.

Quoted 6 lines

We can solve it by explicitly trimming the newline, which is more obvious. Note that we use strbuf_rtrim here, which will actually cut off any trailing whitespace, not just a single newline. This is a good thing, though, as it makes our parsing more liberal (and spaces are not valid in refnames anyway).

While looking into Kyle's earlier response, I found that there is a semi-duplicate of this function for the http-walker side:
http_fetch_ref. It already uses strbuf_rtrim, so I feel doubly good about moving to its use here.

Almost certainly this duplicated functionality could be factored out. I have very little interest in spending time cleaning up the http-push code, though.

-Peff

#2 lore raw
In reply to Jeff King
Quoted 7 lines · Jeff King

When we fetch a symbolic ref file from the remote, we get the whole string "ref: refs/heads/master\n", recognize it by skipping past the "ref: ", and store the rest. We should chomp the trailing newline.
[..]
This is a regression in v2.1.0.

Quoted 5 lines

It was causing t5540 to fail, but I realized I have been building with NO_EXPAT for a while, so I didn't notice. Frankly, I'm kind of surprised and disturbed that nobody noticed it before now. More evidence that we can kill off dumb http-push? I would have thought somebody else would have noticed the test failure, though.

I have this line in my 2.1.4 test output log:

t5540-http-push-webdav.sh .......................... ok

And again in my 2.2.2 test output log:

t5540-http-push-webdav.sh .......................... ok

Running the 2.2.2 version with -v I get:

t5540-http-push-webdav.sh ..
ok 1 - setup remote repository
ok 2 - create password-protected repository
ok 3 - setup askpass helper
ok 4 - clone remote repository
ok 5 - push to remote repository with packed refs
ok 6 - push already up-to-date
ok 7 - push to remote repository with unpacked refs
ok 8 - http-push fetches unpacked objects
ok 9 - http-push fetches packed objects
ok 10 - create and delete remote branch
ok 11 - MKCOL sends directory names with trailing slashes
ok 12 - PUT and MOVE sends object to URLs with SHA-1 hash suffix
ok 13 - non-fast-forward push fails
ok 14 - non-fast-forward push show ref status
ok 15 - non-fast-forward push shows help message
not ok 16 - force with lease aka cas # TODO known breakage
ok 17 - push to password-protected repository (user in URL)
not ok 18 - user was prompted only once for password # TODO known breakage not ok 19 - push to password-protected repository (no user in URL) # TODO known breakage

# still have 3 known breakage(s)
# passed all remaining 16 test(s)
1..19
ok

I also get the same results using v2.3.0-rc0.

I do not build with NO_EXPAT. This is running the tests on OS X without this patch applied. Is something else required to get a failure?

-Kyle

author
#3 lore raw
Quoted 6 lines · Kyle J. McKay

I have this line in my 2.1.4 test output log:

t5540-http-push-webdav.sh .......................... ok [...]
I do not build with NO_EXPAT. This is running the tests on OS X without this patch applied. Is something else required to get a failure?

Hmm. I think it is probably this:

http://curl.haxx.se/docs/adv_20150108B.html

where curl has started complaining about URLs with newlines in them. So ae021d8 did introduce a bug, but older versions of curl did not really care. The combination of ae021d8 with a new version of curl triggers the problem.

And that also explains why it worked prior to eecc8367f4; curl was more forgiving. Also, interestingly, if you "git log -S'- 6' http-push.c", you can see the exact same bug reappear and go away in 2006/2007. The implicit "chop one character" behavior is there in the original 3dfaf7bc, adding http-push support. Then it disappears as a side effect of bfbd0bb6, and then comes back again in eecc8367.

Anyway. I think my patch is still the right thing. But that does explain why we didn't notice the test failure.

-Peff

Tested-by
#4 lore raw
Quoted 9 lines · Jeff King
Quoted 6 lines · Kyle J. McKay

I have this line in my 2.1.4 test output log:

t5540-http-push-webdav.sh .......................... ok [...]
I do not build with NO_EXPAT. This is running the tests on OS X without this patch applied. Is something else required to get a failure?

Quoted 8 lines

Hmm. I think it is probably this:

http://curl.haxx.se/docs/adv_20150108B.html

where curl has started complaining about URLs with newlines in them. So ae021d8 did introduce a bug, but older versions of curl did not really care. The combination of ae021d8 with a new version of curl triggers the problem.

I'm running curl 7.38, and in this context "older" is anything before 7.40, so that would explain it. curl 7.38 was released 2014-09-10, so it's only 4 months old at this point. 7.40 was only released 5 days ago on 2015-01-08 which is probably why there have not been a whole lot of reports about this so far.

Quoted 6 lines

And that also explains why it worked prior to eecc8367f4; curl was more forgiving. Also, interestingly, if you "git log -S'- 6' http-push.c", you can see the exact same bug reappear and go away in 2006/2007. The implicit "chop one character" behavior is there in the original 3dfaf7bc, adding http-push support. Then it disappears as a side effect of bfbd0bb6, and then comes back again in eecc8367.

After updating to curl 7.40 I get:

t5540-http-push-webdav.sh (Wstat: 256 Tests: 19 Failed: 1)
Failed test: 10
Non-zero exit status: 1

Quoted 2 lines

Anyway. I think my patch is still the right thing. But that does explain why we didn't notice the test failure.

And then after applying your patch I'm back to:

t5540-http-push-webdav.sh .. ok

So definitely a needed patch.

-Kyle

#5 lore raw
Quoted 14 lines · Kyle J. McKay

On Jan 13, 2015, at 11:58, Jeff King wrote:
...
I'm running curl 7.38, and in this context "older" is anything before 7.40, so that would explain it. curl 7.38 was released 2014-09-10, so it's only 4 months old at this point. 7.40 was only released 5 days ago on 2015-01-08 which is probably why there have not been a whole lot of reports about this so far.

After updating to curl 7.40 I get:

t5540-http-push-webdav.sh (Wstat: 256 Tests: 19 Failed: 1)
Failed test: 10
Non-zero exit status: 1

Quoted 7 lines
Quoted 3 lines

Anyway. I think my patch is still the right thing. But that does explain
why we didn't notice the test failure.

And then after applying your patch I'm back to:

t5540-http-push-webdav.sh .. ok

I see a Ubuntu box I have nearby has this:

curl (7.35.0-1ubuntu2.3) trusty-security; urgency=medium

* SECURITY UPDATE: URL request injection
- debian/patches/CVE-2014-8150.patch: drop bad chars from URL in lib/url.c, added test to tests/data/Makefile.am, tests/data/test1529, tests/libtest/Makefile.inc, tests/libtest/lib1529.c.
- CVE-2014-8150

-- Marc Deslauriers <[email protected]> Wed, 14 Jan 2015 08:49:32 -0500

That explains why I started seeing the same on a box with 7.35.x which looks older than 7.40.