Fix integer decoding when it takes multiple reads

This commit is contained in:
Tatsuhiro Tsujikawa 2014-07-22 01:50:29 +09:00
parent 139c3b508a
commit 44310c6de5
2 changed files with 22 additions and 8 deletions

View File

@ -360,6 +360,7 @@ int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater)
inflater->huffman_encoded = 0; inflater->huffman_encoded = 0;
inflater->index = 0; inflater->index = 0;
inflater->left = 0; inflater->left = 0;
inflater->shift = 0;
inflater->newnamelen = 0; inflater->newnamelen = 0;
inflater->index_required = 0; inflater->index_required = 0;
inflater->no_index = 0; inflater->no_index = 0;
@ -496,16 +497,20 @@ static size_t encode_length(uint8_t *buf, size_t n, size_t prefix)
* set to nonzero. * set to nonzero.
* *
* This function returns the next byte of read byte. This function * This function returns the next byte of read byte. This function
* stores the decoded integer in |*res| if it succeed, including * stores the decoded integer in |*res| and number of shift to make in
* partial decoding, or stores -1 in |*res|, indicating decoding * the next decoding in |*shift_ptr| if it succeed, including partial
* error. * decoding, or stores -1 in |*res|, indicating decoding error.
*/ */
static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial, static uint8_t* decode_length(ssize_t *res, size_t *shift_ptr, int *final,
ssize_t initial, size_t shift,
uint8_t *in, uint8_t *last, size_t prefix) uint8_t *in, uint8_t *last, size_t prefix)
{ {
int k = (1 << prefix) - 1, r; int k = (1 << prefix) - 1;
ssize_t n = initial; ssize_t n = initial;
*shift_ptr = 0;
*final = 0; *final = 0;
if(n == 0) { if(n == 0) {
if((*in & k) == k) { if((*in & k) == k) {
n = k; n = k;
@ -519,8 +524,8 @@ static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial,
return in; return in;
} }
} }
for(r = 0; in != last; ++in, r += 7) { for(; in != last; ++in, shift += 7) {
n += (*in & 0x7f) << r; n += (*in & 0x7f) << shift;
if(n >= (1 << 16)) { if(n >= (1 << 16)) {
*res = -1; *res = -1;
return in + 1; return in + 1;
@ -529,6 +534,9 @@ static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial,
break; break;
} }
} }
*shift_ptr = shift;
if(in == last) { if(in == last) {
*res = n; *res = n;
return in; return in;
@ -1350,7 +1358,8 @@ static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater,
{ {
uint8_t *nin; uint8_t *nin;
*rfin = 0; *rfin = 0;
nin = decode_length(&inflater->left, rfin, inflater->left, in, last, prefix); nin = decode_length(&inflater->left, &inflater->shift, rfin, inflater->left,
inflater->shift, in, last, prefix);
if(inflater->left == -1) { if(inflater->left == -1) {
DEBUGF(fprintf(stderr, "inflatehd: invalid integer\n")); DEBUGF(fprintf(stderr, "inflatehd: invalid integer\n"));
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
@ -1691,6 +1700,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
} }
} }
inflater->left = 0; inflater->left = 0;
inflater->shift = 0;
break; break;
case NGHTTP2_HD_STATE_CLEAR_REFSET: case NGHTTP2_HD_STATE_CLEAR_REFSET:
clear_refset(&inflater->ctx); clear_refset(&inflater->ctx);
@ -1770,6 +1780,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
hd_inflate_set_huffman_encoded(inflater, in); hd_inflate_set_huffman_encoded(inflater, in);
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN; inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN;
inflater->left = 0; inflater->left = 0;
inflater->shift = 0;
DEBUGF(fprintf(stderr, "inflatehd: huffman encoded=%d\n", DEBUGF(fprintf(stderr, "inflatehd: huffman encoded=%d\n",
inflater->huffman_encoded != 0)); inflater->huffman_encoded != 0));
/* Fall through */ /* Fall through */
@ -1844,6 +1855,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
hd_inflate_set_huffman_encoded(inflater, in); hd_inflate_set_huffman_encoded(inflater, in);
inflater->state = NGHTTP2_HD_STATE_READ_VALUELEN; inflater->state = NGHTTP2_HD_STATE_READ_VALUELEN;
inflater->left = 0; inflater->left = 0;
inflater->shift = 0;
DEBUGF(fprintf(stderr, "inflatehd: huffman encoded=%d\n", DEBUGF(fprintf(stderr, "inflatehd: huffman encoded=%d\n",
inflater->huffman_encoded != 0)); inflater->huffman_encoded != 0));
/* Fall through */ /* Fall through */

View File

@ -168,6 +168,8 @@ struct nghttp2_hd_inflater {
/* The maximum header table size the inflater supports. This is the /* The maximum header table size the inflater supports. This is the
same value transmitted in SETTINGS_HEADER_TABLE_SIZE */ same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
size_t settings_hd_table_bufsize_max; size_t settings_hd_table_bufsize_max;
/* The number of next shift to decode integer */
size_t shift;
nghttp2_hd_opcode opcode; nghttp2_hd_opcode opcode;
nghttp2_hd_inflate_state state; nghttp2_hd_inflate_state state;
/* nonzero if string is huffman encoded */ /* nonzero if string is huffman encoded */