diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index 110de64e..1f7d06cd 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -167,6 +167,10 @@ typedef enum { * The user callback function failed due to the temporal error. */ SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE = -521, + /** + * The length of the frame is too large. + */ + SPDYLAY_ERR_FRAME_TOO_LARGE = -522, /** * The errors < :enum:`SPDYLAY_ERR_FATAL` mean that the library is * under unexpected condition and cannot process any further data diff --git a/lib/spdylay_frame.c b/lib/spdylay_frame.c index dd1897e2..db0aad34 100644 --- a/lib/spdylay_frame.c +++ b/lib/spdylay_frame.c @@ -107,6 +107,11 @@ ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr, return framelen; } framelen += nv_offset; + + if(framelen - SPDYLAY_FRAME_HEAD_LENGTH > SPDYLAY_LENGTH_MASK) { + /* In SPDY/2 and 3, Max frame size is 2**24 - 1. */ + return SPDYLAY_ERR_FRAME_TOO_LARGE; + } return framelen; } diff --git a/lib/spdylay_frame.h b/lib/spdylay_frame.h index a5a481e1..88437577 100644 --- a/lib/spdylay_frame.h +++ b/lib/spdylay_frame.h @@ -35,6 +35,8 @@ #include "spdylay_client_cert_vector.h" #define SPDYLAY_STREAM_ID_MASK 0x7fffffff +/* This is actually the maximum length of a control frame in SPDY/2 + and 3. */ #define SPDYLAY_LENGTH_MASK 0xffffff #define SPDYLAY_VERSION_MASK 0x7fff #define SPDYLAY_DELTA_WINDOW_SIZE_MASK 0x7fffffff @@ -124,6 +126,8 @@ size_t spdylay_frame_get_len_size(uint16_t version); * The version is not supported. * SPDYLAY_ERR_ZLIB * The deflate operation failed. + * SPDYLAY_ERR_FRAME_TOO_LARGE + * The length of the frame is too large. * SPDYLAY_ERR_NOMEM * Out of memory. */ @@ -201,6 +205,8 @@ int spdylay_frame_unpack_syn_stream_without_nv(spdylay_syn_stream *frame, * The version is not supported. * SPDYLAY_ERR_ZLIB * The deflate operation failed. + * SPDYLAY_ERR_FRAME_TOO_LARGE + * The length of the frame is too large. * SPDYLAY_ERR_NOMEM * Out of memory. */ @@ -335,6 +341,8 @@ int spdylay_frame_unpack_goaway(spdylay_goaway *frame, * The version is not supported. * SPDYLAY_ERR_ZLIB * The deflate operation failed. + * SPDYLAY_ERR_FRAME_TOO_LARGE + * The length of the frame is too large. * SPDYLAY_ERR_NOMEM * Out of memory. */ @@ -539,6 +547,8 @@ ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv, size_t len_size); * * SPDYLAY_ERR_ZLIB * The deflate operation failed. + * SPDYLAY_ERR_FRAME_TOO_LARGE + * The length of the frame is too large. * SPDYLAY_ERR_NOMEM * Out of memory. */ diff --git a/lib/spdylay_helper.c b/lib/spdylay_helper.c index 38115e93..6686e829 100644 --- a/lib/spdylay_helper.c +++ b/lib/spdylay_helper.c @@ -119,6 +119,8 @@ const char* spdylay_strerror(int error_code) return "Gzip error"; case SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE: return "The user callback function failed due to the temporal error"; + case SPDYLAY_ERR_FRAME_TOO_LARGE: + return "The length of the frame is too large"; case SPDYLAY_ERR_NOMEM: return "Out of memory"; case SPDYLAY_ERR_CALLBACK_FAILURE: diff --git a/lib/spdylay_int.h b/lib/spdylay_int.h index 0113502c..02fcd69e 100644 --- a/lib/spdylay_int.h +++ b/lib/spdylay_int.h @@ -38,8 +38,7 @@ typedef int (*spdylay_compar)(const void *lhs, const void *rhs); /* Internal error code. They must be in the range [-499, -100], inclusive. */ typedef enum { - SPDYLAY_ERR_CREDENTIAL_PENDING = -101, - SPDYLAY_ERR_FRAME_TOO_LARGE = -102 + SPDYLAY_ERR_CREDENTIAL_PENDING = -101 } spdylay_internal_error; #endif /* SPDYLAY_INT_H */ diff --git a/tests/main.c b/tests/main.c index 831fd40b..131b6454 100644 --- a/tests/main.c +++ b/tests/main.c @@ -186,6 +186,8 @@ int main(int argc, char* argv[]) test_spdylay_frame_pack_syn_stream_spdy2) || !CU_add_test(pSuite, "frame_pack_syn_stream_spdy3", test_spdylay_frame_pack_syn_stream_spdy3) || + !CU_add_test(pSuite, "frame_pack_syn_stream_frame_too_large", + test_spdylay_frame_pack_syn_stream_frame_too_large) || !CU_add_test(pSuite, "frame_pack_syn_reply_spdy2", test_spdylay_frame_pack_syn_reply_spdy2) || !CU_add_test(pSuite, "frame_pack_syn_reply_spdy3", diff --git a/tests/spdylay_frame_test.c b/tests/spdylay_frame_test.c index da832977..2c52abc3 100644 --- a/tests/spdylay_frame_test.c +++ b/tests/spdylay_frame_test.c @@ -346,6 +346,35 @@ void test_spdylay_frame_pack_syn_stream_spdy3(void) test_spdylay_frame_pack_syn_stream_version(SPDYLAY_PROTO_SPDY3); } +void test_spdylay_frame_pack_syn_stream_frame_too_large(void) +{ + spdylay_zlib deflater; + spdylay_frame frame; + uint8_t *buf = NULL, *nvbuf = NULL; + size_t buflen = 0, nvbuflen = 0; + ssize_t framelen; + size_t big_vallen = 16777215; + char *big_val = malloc(big_vallen + 1); + const char *big_hds[] = { "header", big_val, NULL }; + memset(big_val, '0', big_vallen); + big_val[big_vallen] = '\0'; + + spdylay_zlib_deflate_hd_init(&deflater, SPDYLAY_PROTO_SPDY3); + spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY3, + SPDYLAY_CTRL_FLAG_FIN, 65536, 1000000007, 3, + spdylay_frame_nv_copy(big_hds)); + framelen = spdylay_frame_pack_syn_stream(&buf, &buflen, + &nvbuf, &nvbuflen, + &frame.syn_stream, &deflater); + CU_ASSERT_EQUAL(SPDYLAY_ERR_FRAME_TOO_LARGE, framelen); + + spdylay_frame_syn_stream_free(&frame.syn_stream); + free(buf); + free(nvbuf); + free(big_val); + spdylay_zlib_deflate_free(&deflater); +} + static void test_spdylay_frame_pack_syn_reply_version(uint16_t version) { spdylay_zlib deflater, inflater; diff --git a/tests/spdylay_frame_test.h b/tests/spdylay_frame_test.h index 7a513da3..56780869 100644 --- a/tests/spdylay_frame_test.h +++ b/tests/spdylay_frame_test.h @@ -35,6 +35,7 @@ void test_spdylay_frame_pack_goaway_spdy2(void); void test_spdylay_frame_pack_goaway_spdy3(void); void test_spdylay_frame_pack_syn_stream_spdy2(void); void test_spdylay_frame_pack_syn_stream_spdy3(void); +void test_spdylay_frame_pack_syn_stream_frame_too_large(void); void test_spdylay_frame_pack_syn_reply_spdy2(void); void test_spdylay_frame_pack_syn_reply_spdy3(void); void test_spdylay_frame_pack_headers_spdy2(void);