git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/2] Harden url.c URL-decoding logic
@ 2019-06-03 20:45 Matthew DeVore
  2019-06-03 20:45 ` [PATCH 1/2] url: do not read past end of buffer Matthew DeVore
  2019-06-03 20:45 ` [PATCH 2/2] url: do not allow %00 to represent NULL in URLs Matthew DeVore
  0 siblings, 2 replies; 9+ messages in thread
From: Matthew DeVore @ 2019-06-03 20:45 UTC (permalink / raw)
  To: git; +Cc: Matthew DeVore, jeffhost, l.s.r, gitster, spearce, jrn

Fixing two minor issues related to string-handling corner cases in url.c

Thanks,

Matthew DeVore (2):
  url: do not read past end of buffer
  url: do not allow %00 to represent NULL in URLs

 url.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/2] url: do not read past end of buffer
  2019-06-03 20:45 [PATCH 0/2] Harden url.c URL-decoding logic Matthew DeVore
@ 2019-06-03 20:45 ` Matthew DeVore
  2019-06-04  5:00   ` René Scharfe
  2019-06-03 20:45 ` [PATCH 2/2] url: do not allow %00 to represent NULL in URLs Matthew DeVore
  1 sibling, 1 reply; 9+ messages in thread
From: Matthew DeVore @ 2019-06-03 20:45 UTC (permalink / raw)
  To: git; +Cc: Matthew DeVore, jeffhost, l.s.r, gitster, spearce, jrn

url_decode_internal could have been tricked into reading past the length
of the **query buffer if there are fewer than 2 characters after a % (in
a null-terminated string, % would have to be the last character).
Prevent this from happening by checking len before decoding the %
sequence.

Signed-off-by: Matthew DeVore <matvore@google.com>
---
 url.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/url.c b/url.c
index 25576c390b..c0bb4e23c3 100644
--- a/url.c
+++ b/url.c
@@ -39,21 +39,21 @@ static char *url_decode_internal(const char **query, int len,
 		unsigned char c = *q;
 
 		if (!c)
 			break;
 		if (stop_at && strchr(stop_at, c)) {
 			q++;
 			len--;
 			break;
 		}
 
-		if (c == '%') {
+		if (c == '%' && len >= 3) {
 			int val = hex2chr(q + 1);
 			if (0 <= val) {
 				strbuf_addch(out, val);
 				q += 3;
 				len -= 3;
 				continue;
 			}
 		}
 
 		if (decode_plus && c == '+')
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] url: do not allow %00 to represent NULL in URLs
  2019-06-03 20:45 [PATCH 0/2] Harden url.c URL-decoding logic Matthew DeVore
  2019-06-03 20:45 ` [PATCH 1/2] url: do not read past end of buffer Matthew DeVore
@ 2019-06-03 20:45 ` Matthew DeVore
  2019-06-04  1:02   ` brian m. carlson
  2019-06-04  5:01   ` René Scharfe
  1 sibling, 2 replies; 9+ messages in thread
From: Matthew DeVore @ 2019-06-03 20:45 UTC (permalink / raw)
  To: git; +Cc: Matthew DeVore, jeffhost, l.s.r, gitster, spearce, jrn

There is no reason to allow %00 to terminate a string, so do not allow it.
Otherwise, we end up returning arbitrary content in the string (that which is
after the %00) which is effectively hidden from callers and can escape sanity
checks and validation, and possible be used in tandem with a security
vulnerability to introduce a payload.

Signed-off-by: Matthew DeVore <matvore@google.com>
---
 url.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/url.c b/url.c
index c0bb4e23c3..cf791cb139 100644
--- a/url.c
+++ b/url.c
@@ -41,21 +41,21 @@ static char *url_decode_internal(const char **query, int len,
 		if (!c)
 			break;
 		if (stop_at && strchr(stop_at, c)) {
 			q++;
 			len--;
 			break;
 		}
 
 		if (c == '%' && len >= 3) {
 			int val = hex2chr(q + 1);
-			if (0 <= val) {
+			if (0 < val) {
 				strbuf_addch(out, val);
 				q += 3;
 				len -= 3;
 				continue;
 			}
 		}
 
 		if (decode_plus && c == '+')
 			strbuf_addch(out, ' ');
 		else
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] url: do not allow %00 to represent NULL in URLs
  2019-06-03 20:45 ` [PATCH 2/2] url: do not allow %00 to represent NULL in URLs Matthew DeVore
@ 2019-06-04  1:02   ` brian m. carlson
  2019-06-04 17:38     ` Matthew DeVore
  2019-06-04  5:01   ` René Scharfe
  1 sibling, 1 reply; 9+ messages in thread
From: brian m. carlson @ 2019-06-04  1:02 UTC (permalink / raw)
  To: Matthew DeVore; +Cc: git, jeffhost, l.s.r, gitster, spearce, jrn

[-- Attachment #1: Type: text/plain, Size: 1433 bytes --]

On 2019-06-03 at 20:45:26, Matthew DeVore wrote:
> There is no reason to allow %00 to terminate a string, so do not allow it.
> Otherwise, we end up returning arbitrary content in the string (that which is
> after the %00) which is effectively hidden from callers and can escape sanity
> checks and validation, and possible be used in tandem with a security
> vulnerability to introduce a payload.

So I think the reason you've stated is good and I agree that we
shouldn't decode data we're not going to use. However, I'm also
interested in the cases in which we decode data and don't want to allow
NULs, because we should, in general, allow bizarre URLs as long as
they're URL-encoded.

It looks like several of the places we do this are in the credential
manager code, and I think I can agree that usernames and passwords
should not contain NUL characters (for Basic auth, RFC 7617 prohibits
it). It also seems that the credential code decodes the path parameter
before passing it on, which is unfortunate, but can't be changed for
backward compatibility reasons.

And then the other instances are a file: URL in remote-testsvn.c and
query parameters that have no reason to contain NULs in http-backend.c.

So I think overall this is fine, although we probably want to change the
commit summary to say "NUL" instead of "NULL".
-- 
brian m. carlson: Houston, Texas, US
OpenPGP: https://keybase.io/bk2204

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 868 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] url: do not read past end of buffer
  2019-06-03 20:45 ` [PATCH 1/2] url: do not read past end of buffer Matthew DeVore
@ 2019-06-04  5:00   ` René Scharfe
  2019-06-04 17:22     ` Matthew DeVore
  0 siblings, 1 reply; 9+ messages in thread
From: René Scharfe @ 2019-06-04  5:00 UTC (permalink / raw)
  To: Matthew DeVore, git; +Cc: jeffhost, gitster, spearce, jrn, Jeff King

Am 03.06.19 um 22:45 schrieb Matthew DeVore:
> url_decode_internal could have been tricked into reading past the length
> of the **query buffer if there are fewer than 2 characters after a % (in
> a null-terminated string, % would have to be the last character).
> Prevent this from happening by checking len before decoding the %
> sequence.
>
> Signed-off-by: Matthew DeVore <matvore@google.com>
> ---
>  url.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/url.c b/url.c
> index 25576c390b..c0bb4e23c3 100644
> --- a/url.c
> +++ b/url.c
> @@ -39,21 +39,21 @@ static char *url_decode_internal(const char **query, int len,
>  		unsigned char c = *q;
>
>  		if (!c)
>  			break;
>  		if (stop_at && strchr(stop_at, c)) {
>  			q++;
>  			len--;
>  			break;
>  		}
>
> -		if (c == '%') {
> +		if (c == '%' && len >= 3) {

Tricky.  hex2chr() makes sure to not run over the end of NUL-terminated
strings, but url_decode_internal() is supposed to honor the parameter
len as well.  Your change disables %-decoding for the two callers that
pass -1 as len, though.  So perhaps like this?

		if (c == '%' && (len < 0 || len >= 3)) {

In any case: Good find!

>  			int val = hex2chr(q + 1);
>  			if (0 <= val) {
>  				strbuf_addch(out, val);
>  				q += 3;
>  				len -= 3;
>  				continue;
>  			}
>  		}
>
>  		if (decode_plus && c == '+')
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] url: do not allow %00 to represent NULL in URLs
  2019-06-03 20:45 ` [PATCH 2/2] url: do not allow %00 to represent NULL in URLs Matthew DeVore
  2019-06-04  1:02   ` brian m. carlson
@ 2019-06-04  5:01   ` René Scharfe
  2019-06-04 17:23     ` Matthew DeVore
  1 sibling, 1 reply; 9+ messages in thread
From: René Scharfe @ 2019-06-04  5:01 UTC (permalink / raw)
  To: Matthew DeVore, git; +Cc: jeffhost, gitster, spearce, jrn, Jeff King

Am 03.06.19 um 22:45 schrieb Matthew DeVore:
> There is no reason to allow %00 to terminate a string, so do not allow it.
> Otherwise, we end up returning arbitrary content in the string (that which is
> after the %00) which is effectively hidden from callers and can escape sanity
> checks and validation, and possible be used in tandem with a security
> vulnerability to introduce a payload.

It's a bit hard to see with the (extended, but still) limited context,
but url_decode_internal() effectively returns a NUL-terminated string,
even though it does use a strbuf parameter named "out" for temporary
storage.  So callers really have no use for decoded NULs, and this
change thus makes sense to me.

>
> Signed-off-by: Matthew DeVore <matvore@google.com>
> ---
>  url.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/url.c b/url.c
> index c0bb4e23c3..cf791cb139 100644
> --- a/url.c
> +++ b/url.c
> @@ -41,21 +41,21 @@ static char *url_decode_internal(const char **query, int len,
>  		if (!c)
>  			break;
>  		if (stop_at && strchr(stop_at, c)) {
>  			q++;
>  			len--;
>  			break;
>  		}
>
>  		if (c == '%' && len >= 3) {
>  			int val = hex2chr(q + 1);
> -			if (0 <= val) {
> +			if (0 < val) {
>  				strbuf_addch(out, val);
>  				q += 3;
>  				len -= 3;
>  				continue;
>  			}
>  		}
>
>  		if (decode_plus && c == '+')
>  			strbuf_addch(out, ' ');
>  		else
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] url: do not read past end of buffer
  2019-06-04  5:00   ` René Scharfe
@ 2019-06-04 17:22     ` Matthew DeVore
  0 siblings, 0 replies; 9+ messages in thread
From: Matthew DeVore @ 2019-06-04 17:22 UTC (permalink / raw)
  To: René Scharfe
  Cc: Matthew DeVore, git, jeffhost, gitster, spearce, jrn, Jeff King

On Tue, Jun 04, 2019 at 07:00:34AM +0200, René Scharfe wrote:
> Am 03.06.19 um 22:45 schrieb Matthew DeVore:
> > url_decode_internal could have been tricked into reading past the length
> > of the **query buffer if there are fewer than 2 characters after a % (in
> > a null-terminated string, % would have to be the last character).
> > Prevent this from happening by checking len before decoding the %
> > sequence.
> >
> > Signed-off-by: Matthew DeVore <matvore@google.com>
> > ---
> >  url.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/url.c b/url.c
> > index 25576c390b..c0bb4e23c3 100644
> > --- a/url.c
> > +++ b/url.c
> > @@ -39,21 +39,21 @@ static char *url_decode_internal(const char **query, int len,
> >  		unsigned char c = *q;
> >
> >  		if (!c)
> >  			break;
> >  		if (stop_at && strchr(stop_at, c)) {
> >  			q++;
> >  			len--;
> >  			break;
> >  		}
> >
> > -		if (c == '%') {
> > +		if (c == '%' && len >= 3) {
> 
> Tricky.  hex2chr() makes sure to not run over the end of NUL-terminated
> strings, but url_decode_internal() is supposed to honor the parameter
> len as well.  Your change disables %-decoding for the two callers that
> pass -1 as len, though.  So perhaps like this?
> 
> 		if (c == '%' && (len < 0 || len >= 3)) {

I've applied this and will include it in the next roll-up. Thank you for
catching it. (I'm disappointed that I missed it and that there were no tests to
catch the mistake.)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] url: do not allow %00 to represent NULL in URLs
  2019-06-04  5:01   ` René Scharfe
@ 2019-06-04 17:23     ` Matthew DeVore
  0 siblings, 0 replies; 9+ messages in thread
From: Matthew DeVore @ 2019-06-04 17:23 UTC (permalink / raw)
  To: René Scharfe
  Cc: Matthew DeVore, git, jeffhost, gitster, spearce, jrn, Jeff King

On Tue, Jun 04, 2019 at 07:01:01AM +0200, René Scharfe wrote:
> It's a bit hard to see with the (extended, but still) limited context,
> but url_decode_internal() effectively returns a NUL-terminated string,
> even though it does use a strbuf parameter named "out" for temporary
> storage.  So callers really have no use for decoded NULs, and this
> change thus makes sense to me.
> 

That was more or less my train of thought as well. Thank you for taking a look.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] url: do not allow %00 to represent NULL in URLs
  2019-06-04  1:02   ` brian m. carlson
@ 2019-06-04 17:38     ` Matthew DeVore
  0 siblings, 0 replies; 9+ messages in thread
From: Matthew DeVore @ 2019-06-04 17:38 UTC (permalink / raw)
  To: brian m. carlson, Matthew DeVore, git, jeffhost, l.s.r, gitster,
	spearce, jrn

On Tue, Jun 04, 2019 at 01:02:43AM +0000, brian m. carlson wrote:
> It looks like several of the places we do this are in the credential
> manager code, and I think I can agree that usernames and passwords
> should not contain NUL characters (for Basic auth, RFC 7617 prohibits
> it). It also seems that the credential code decodes the path parameter
> before passing it on, which is unfortunate, but can't be changed for
> backward compatibility reasons.
> 
> And then the other instances are a file: URL in remote-testsvn.c and
> query parameters that have no reason to contain NULs in http-backend.c.

OK. Good to know that there is no justification to support %00 in URLs.

> So I think overall this is fine, although we probably want to change the
> commit summary to say "NUL" instead of "NULL".

Applied for the next roll-up. Thank you for taking a look.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-06-04 17:38 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-03 20:45 [PATCH 0/2] Harden url.c URL-decoding logic Matthew DeVore
2019-06-03 20:45 ` [PATCH 1/2] url: do not read past end of buffer Matthew DeVore
2019-06-04  5:00   ` René Scharfe
2019-06-04 17:22     ` Matthew DeVore
2019-06-03 20:45 ` [PATCH 2/2] url: do not allow %00 to represent NULL in URLs Matthew DeVore
2019-06-04  1:02   ` brian m. carlson
2019-06-04 17:38     ` Matthew DeVore
2019-06-04  5:01   ` René Scharfe
2019-06-04 17:23     ` Matthew DeVore

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).