diff --git a/bin/varnishd/http2/cache_http2_hpack.c b/bin/varnishd/http2/cache_http2_hpack.c index d432629..b0dacb9 100644 --- a/bin/varnishd/http2/cache_http2_hpack.c +++ b/bin/varnishd/http2/cache_http2_hpack.c @@ -93,18 +93,25 @@ static h2_error h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len) { /* XXX: This might belong in cache/cache_http.c */ + const char *b0; unsigned n; + int disallow_empty; + char *p; + int i; CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); AN(b); assert(namelen >= 2); /* 2 chars from the ': ' that we added */ assert(namelen <= len); + + disallow_empty = 0; if (len > UINT_MAX) { /* XXX: cache_param max header size */ VSLb(hp->vsl, SLT_BogoHeader, "Header too large: %.20s", b); return (H2SE_ENHANCE_YOUR_CALM); } + b0 = b; if (b[0] == ':') { /* Match H/2 pseudo headers */ /* XXX: Should probably have some include tbl for @@ -113,10 +120,24 @@ h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len) b += namelen; len -= namelen; n = HTTP_HDR_METHOD; + disallow_empty = 1; + + /* First field cannot contain SP or CTL */ + for (p = b, i = 0; i < len; p++, i++) { + if (vct_issp(*p) || vct_isctl(*p)) + return (H2SE_PROTOCOL_ERROR); + } } else if (!strncmp(b, ":path: ", namelen)) { b += namelen; len -= namelen; n = HTTP_HDR_URL; + disallow_empty = 1; + + /* Second field cannot contain LWS or CTL */ + for (p = b, i = 0; i < len; p++, i++) { + if (vct_islws(*p) || vct_isctl(*p)) + return (H2SE_PROTOCOL_ERROR); + } } else if (!strncmp(b, ":scheme: ", namelen)) { /* XXX: What to do about this one? (typically "http" or "https"). For now set it as a normal @@ -124,6 +145,15 @@ h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len) b++; len-=1; n = hp->nhd; + + for (p = b + namelen, i = 0; i < len-namelen; + p++, i++) { + if (vct_issp(*p) || vct_isctl(*p)) + return (H2SE_PROTOCOL_ERROR); + } + + if (!i) + return (H2SE_PROTOCOL_ERROR); } else if (!strncmp(b, ":authority: ", namelen)) { b+=6; len-=6; @@ -160,6 +190,13 @@ h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len) hp->hd[n].b = b; hp->hd[n].e = b + len; + if (disallow_empty && !Tlen(hp->hd[n])) { + VSLb(hp->vsl, SLT_BogoHeader, + "Empty pseudo-header %.*s", + (int)namelen, b0); + return (H2SE_PROTOCOL_ERROR); + } + return (0); }