Fix treatment of padding

This commit is contained in:
Tatsuhiro Tsujikawa 2018-04-22 12:00:55 +09:00
parent e04de48ed9
commit 06379b2861
4 changed files with 103 additions and 4 deletions

View File

@ -5800,8 +5800,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
case NGHTTP2_HEADERS: case NGHTTP2_HEADERS:
if (iframe->padlen == 0 && if (iframe->padlen == 0 &&
(iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) {
pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags);
padlen = inbound_frame_compute_pad(iframe); padlen = inbound_frame_compute_pad(iframe);
if (padlen < 0) { if (padlen < 0 ||
(size_t)padlen + pri_fieldlen > 1 + iframe->payloadleft) {
busy = 1; busy = 1;
rv = nghttp2_session_terminate_session_with_reason( rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: invalid padding"); session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: invalid padding");
@ -5813,8 +5815,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
} }
iframe->frame.headers.padlen = (size_t)padlen; iframe->frame.headers.padlen = (size_t)padlen;
pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags);
if (pri_fieldlen > 0) { if (pri_fieldlen > 0) {
if (iframe->payloadleft < pri_fieldlen) { if (iframe->payloadleft < pri_fieldlen) {
busy = 1; busy = 1;
@ -5877,8 +5877,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (iframe->padlen == 0 && if (iframe->padlen == 0 &&
(iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) {
padlen = inbound_frame_compute_pad(iframe); padlen = inbound_frame_compute_pad(iframe);
if (padlen < 0) { if (padlen < 0 || (size_t)padlen + 4 /* promised stream id */
> 1 + iframe->payloadleft) {
busy = 1; busy = 1;
rv = nghttp2_session_terminate_session_with_reason( rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, session, NGHTTP2_PROTOCOL_ERROR,
"PUSH_PROMISE: invalid padding"); "PUSH_PROMISE: invalid padding");
@ -6028,6 +6030,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
data_readlen = inbound_frame_effective_readlen( data_readlen = inbound_frame_effective_readlen(
iframe, iframe->payloadleft - readlen, readlen); iframe, iframe->payloadleft - readlen, readlen);
if (data_readlen == -1) {
/* everything is padding */
data_readlen = 0;
}
trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen);
final = (iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) && final = (iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) &&

View File

@ -87,6 +87,8 @@ int main() {
test_nghttp2_session_recv_continuation) || test_nghttp2_session_recv_continuation) ||
!CU_add_test(pSuite, "session_recv_headers_with_priority", !CU_add_test(pSuite, "session_recv_headers_with_priority",
test_nghttp2_session_recv_headers_with_priority) || test_nghttp2_session_recv_headers_with_priority) ||
!CU_add_test(pSuite, "session_recv_headers_with_padding",
test_nghttp2_session_recv_headers_with_padding) ||
!CU_add_test(pSuite, "session_recv_headers_early_response", !CU_add_test(pSuite, "session_recv_headers_early_response",
test_nghttp2_session_recv_headers_early_response) || test_nghttp2_session_recv_headers_early_response) ||
!CU_add_test(pSuite, "session_server_recv_push_response", !CU_add_test(pSuite, "session_server_recv_push_response",

View File

@ -1575,6 +1575,94 @@ void test_nghttp2_session_recv_headers_with_priority(void) {
nghttp2_session_del(session); nghttp2_session_del(session);
} }
void test_nghttp2_session_recv_headers_with_padding(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_bufs bufs;
nghttp2_buf *buf;
nghttp2_frame_hd hd;
nghttp2_outbound_item *item;
my_user_data ud;
ssize_t rv;
frame_pack_bufs_init(&bufs);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.on_frame_recv_callback = on_frame_recv_callback;
callbacks.send_callback = null_send_callback;
/* HEADERS: Wrong padding length */
nghttp2_session_server_new(&session, &callbacks, &ud);
nghttp2_session_send(session);
nghttp2_frame_hd_init(&hd, 10, NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY |
NGHTTP2_FLAG_PADDED,
1);
buf = &bufs.head->buf;
nghttp2_frame_pack_frame_hd(buf->last, &hd);
buf->last += NGHTTP2_FRAME_HDLEN;
/* padding is 6 bytes */
*buf->last++ = 5;
/* priority field */
nghttp2_put_uint32be(buf->last, 3);
buf->last += sizeof(uint32_t);
*buf->last++ = 1;
/* rest is garbage */
memset(buf->last, 0, 4);
buf->last += 4;
ud.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
CU_ASSERT(0 == ud.frame_recv_cb_called);
item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NULL != item);
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
nghttp2_bufs_reset(&bufs);
nghttp2_session_del(session);
/* PUSH_PROMISE: Wrong padding length */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_send(session);
open_sent_stream(session, 1);
nghttp2_frame_hd_init(&hd, 9, NGHTTP2_PUSH_PROMISE,
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PADDED, 1);
buf = &bufs.head->buf;
nghttp2_frame_pack_frame_hd(buf->last, &hd);
buf->last += NGHTTP2_FRAME_HDLEN;
/* padding is 6 bytes */
*buf->last++ = 5;
/* promised stream ID field */
nghttp2_put_uint32be(buf->last, 2);
buf->last += sizeof(uint32_t);
/* rest is garbage */
memset(buf->last, 0, 4);
buf->last += 4;
ud.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
CU_ASSERT(0 == ud.frame_recv_cb_called);
item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NULL != item);
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
nghttp2_bufs_free(&bufs);
nghttp2_session_del(session);
}
static int response_on_begin_frame_callback(nghttp2_session *session, static int response_on_begin_frame_callback(nghttp2_session *session,
const nghttp2_frame_hd *hd, const nghttp2_frame_hd *hd,
void *user_data) { void *user_data) {

View File

@ -37,6 +37,7 @@ void test_nghttp2_session_recv_data(void);
void test_nghttp2_session_recv_data_no_auto_flow_control(void); void test_nghttp2_session_recv_data_no_auto_flow_control(void);
void test_nghttp2_session_recv_continuation(void); void test_nghttp2_session_recv_continuation(void);
void test_nghttp2_session_recv_headers_with_priority(void); void test_nghttp2_session_recv_headers_with_priority(void);
void test_nghttp2_session_recv_headers_with_padding(void);
void test_nghttp2_session_recv_headers_early_response(void); void test_nghttp2_session_recv_headers_early_response(void);
void test_nghttp2_session_server_recv_push_response(void); void test_nghttp2_session_server_recv_push_response(void);
void test_nghttp2_session_recv_premature_headers(void); void test_nghttp2_session_recv_premature_headers(void);