mirror of
https://github.com/curl/curl.git
synced 2026-04-11 12:01:42 +08:00
curl_quiche: refuse headers with CR, LF or null bytes
Also renamed the struct field to 'h1hdr' from 'scratch' to better say what its purpose is. Closes #20101
This commit is contained in:
parent
0e054134b7
commit
6842d4ec4d
@ -88,7 +88,7 @@ struct cf_quiche_ctx {
|
||||
struct curltime started_at; /* time the current attempt started */
|
||||
struct curltime handshake_at; /* time connect handshake finished */
|
||||
struct uint_hash streams; /* hash `data->mid` to `stream_ctx` */
|
||||
struct dynbuf scratch; /* temp buffer for header construction */
|
||||
struct dynbuf h1hdr; /* temp buffer for header construction */
|
||||
struct bufq writebuf; /* temp buffer for writing bodies */
|
||||
curl_off_t data_recvd;
|
||||
BIT(initialized);
|
||||
@ -118,7 +118,7 @@ static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
|
||||
debug_log_init = 1;
|
||||
}
|
||||
#endif
|
||||
curlx_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
|
||||
curlx_dyn_init(&ctx->h1hdr, CURL_MAX_HTTP_HEADER);
|
||||
Curl_uint32_hash_init(&ctx->streams, 63, h3_stream_hash_free);
|
||||
Curl_bufq_init2(&ctx->writebuf, H3_STREAM_CHUNK_SIZE, H3_STREAM_RECV_CHUNKS,
|
||||
BUFQ_OPT_SOFT_LIMIT);
|
||||
@ -135,7 +135,7 @@ static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx)
|
||||
Curl_ssl_peer_cleanup(&ctx->peer);
|
||||
vquic_ctx_free(&ctx->q);
|
||||
Curl_uint32_hash_destroy(&ctx->streams);
|
||||
curlx_dyn_free(&ctx->scratch);
|
||||
curlx_dyn_free(&ctx->h1hdr);
|
||||
Curl_bufq_free(&ctx->writebuf);
|
||||
}
|
||||
curlx_free(ctx);
|
||||
@ -351,6 +351,19 @@ struct cb_ctx {
|
||||
struct h3_stream_ctx *stream;
|
||||
};
|
||||
|
||||
static bool is_valid_h3_header(const uint8_t *hdr, size_t hlen)
|
||||
{
|
||||
while(hlen--) {
|
||||
switch(*hdr++) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\0':
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int cb_each_header(uint8_t *name, size_t name_len,
|
||||
uint8_t *value, size_t value_len,
|
||||
void *argp)
|
||||
@ -360,46 +373,50 @@ static int cb_each_header(uint8_t *name, size_t name_len,
|
||||
struct Curl_easy *data = x->data;
|
||||
struct h3_stream_ctx *stream = x->stream;
|
||||
struct cf_quiche_ctx *ctx = cf->ctx;
|
||||
CURLcode result;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(!stream || stream->xfer_result)
|
||||
return 1; /* abort iteration */
|
||||
|
||||
if((name_len == 7) && !strncmp(HTTP_PSEUDO_STATUS, (char *)name, 7)) {
|
||||
curlx_dyn_reset(&ctx->scratch);
|
||||
if((name_len == 7) && !strncmp(HTTP_PSEUDO_STATUS, (char *)name, 7) &&
|
||||
is_valid_h3_header(value, value_len)) {
|
||||
curlx_dyn_reset(&ctx->h1hdr);
|
||||
result = Curl_http_decode_status(&stream->status_code,
|
||||
(const char *)value, value_len);
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 "));
|
||||
result = curlx_dyn_addn(&ctx->h1hdr, STRCONST("HTTP/3 "));
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->scratch,
|
||||
(const char *)value, value_len);
|
||||
result = curlx_dyn_addn(&ctx->h1hdr, (const char *)value, value_len);
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
|
||||
result = curlx_dyn_addn(&ctx->h1hdr, STRCONST(" \r\n"));
|
||||
if(!result)
|
||||
cf_quiche_write_hd(cf, data, stream, curlx_dyn_ptr(&ctx->scratch),
|
||||
curlx_dyn_len(&ctx->scratch), FALSE);
|
||||
cf_quiche_write_hd(cf, data, stream, curlx_dyn_ptr(&ctx->h1hdr),
|
||||
curlx_dyn_len(&ctx->h1hdr), FALSE);
|
||||
CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s",
|
||||
stream->id, curlx_dyn_ptr(&ctx->scratch));
|
||||
stream->id, curlx_dyn_ptr(&ctx->h1hdr));
|
||||
}
|
||||
else {
|
||||
/* store as an HTTP1-style header */
|
||||
CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
|
||||
stream->id, (int)name_len, name,
|
||||
(int)value_len, value);
|
||||
curlx_dyn_reset(&ctx->scratch);
|
||||
result = curlx_dyn_addn(&ctx->scratch,
|
||||
(const char *)name, name_len);
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->scratch, STRCONST(": "));
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->scratch,
|
||||
(const char *)value, value_len);
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
|
||||
if(!result)
|
||||
cf_quiche_write_hd(cf, data, stream, curlx_dyn_ptr(&ctx->scratch),
|
||||
curlx_dyn_len(&ctx->scratch), FALSE);
|
||||
if(is_valid_h3_header(value, value_len) &&
|
||||
is_valid_h3_header(name, name_len)) {
|
||||
/* store as an HTTP1-style header */
|
||||
CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
|
||||
stream->id, (int)name_len, name,
|
||||
(int)value_len, value);
|
||||
curlx_dyn_reset(&ctx->h1hdr);
|
||||
result = curlx_dyn_addn(&ctx->h1hdr, (const char *)name, name_len);
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->h1hdr, STRCONST(": "));
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->h1hdr, (const char *)value, value_len);
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&ctx->h1hdr, STRCONST("\r\n"));
|
||||
if(!result)
|
||||
cf_quiche_write_hd(cf, data, stream, curlx_dyn_ptr(&ctx->h1hdr),
|
||||
curlx_dyn_len(&ctx->h1hdr), FALSE);
|
||||
}
|
||||
else
|
||||
CURL_TRC_CF(x->data, x->cf, "[%" PRIu64 "] ignore %zu bytes bad header",
|
||||
stream->id, value_len + name_len);
|
||||
}
|
||||
|
||||
if(result) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user