kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 437f2e9ed2c56173412c27658ac9619d91aebaba
parent 521d4d215e17cd3ba4894d29be2938da07a99d08
Author: Joris Vink <joris@coders.se>
Date:   Tue,  6 May 2014 12:24:21 +0200

Be paranoia when it comes to using client supplied integers

Diffstat:
src/spdy.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 72 insertions(+), 40 deletions(-)

diff --git a/src/spdy.c b/src/spdy.c @@ -56,13 +56,18 @@ spdy_frame_recv(struct netbuf *nb) ctrl.flags = *(u_int8_t *)(nb->buf + 4); ctrl.length = net_read32(nb->buf + 4) & 0xffffff; - kore_debug("type is %d", ctrl.type); - kore_debug("version is %d", ctrl.version); - kore_debug("length is %d", ctrl.length); - kore_debug("flags are %d", ctrl.flags); + kore_debug("type is %u", ctrl.type); + kore_debug("version is %u", ctrl.version); + kore_debug("length is %u", ctrl.length); + kore_debug("flags are %u", ctrl.flags); + + if ((int)ctrl.length < 0) { + spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); + return (KORE_RESULT_OK); + } if (ctrl.version != 3) { - kore_debug("protocol mismatch (recv version %d)", + kore_debug("protocol mismatch (recv version %u)", ctrl.version); spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); @@ -93,7 +98,7 @@ spdy_frame_recv(struct netbuf *nb) if (cb != NULL) { r = net_recv_expand(c, nb, ctrl.length, cb); } else { - kore_debug("no callback for type %d", ctrl.type); + kore_debug("no callback for type %u", ctrl.type); r = KORE_RESULT_OK; } } else { @@ -107,9 +112,12 @@ spdy_frame_recv(struct netbuf *nb) } else { data.flags = *(u_int8_t *)(nb->buf + 4); data.length = net_read32(nb->buf + 4) & 0xffffff; - - r = net_recv_expand(c, nb, data.length, - spdy_data_frame_recv); + if ((int)data.length < 0) { + r = KORE_RESULT_ERROR; + } else { + r = net_recv_expand(c, nb, data.length, + spdy_data_frame_recv); + } } } @@ -130,7 +138,7 @@ spdy_frame_send(struct connection *c, u_int16_t type, u_int8_t flags, u_int8_t nb[16]; u_int32_t length; - kore_debug("spdy_frame_send(%p, %d, %d, %d, %p, %d)", + kore_debug("spdy_frame_send(%p, %u, %u, %u, %p, %u)", c, type, flags, len, s, misc); length = 0; @@ -299,14 +307,14 @@ spdy_stream_get_header(struct spdy_header_block *s, char *header, char **out) for (i = 0; i < s->header_pairs; i++) { nlen = net_read32(p); - if ((p + nlen + 4) > end) { - kore_debug("nlen out of bounds on %d (%d)", i, nlen); + if ((int)nlen < 0 || (p + nlen + 4) > end) { + kore_debug("nlen out of bounds on %u (%u)", i, nlen); return (KORE_RESULT_ERROR); } vlen = net_read32(p + nlen + 4); - if ((p + nlen + vlen + 8) > end) { - kore_debug("vlen out of bounds on %d (%d)", i, vlen); + if ((int)vlen < 0 || (p + nlen + vlen + 8) > end) { + kore_debug("vlen out of bounds on %u (%u)", i, vlen); return (KORE_RESULT_ERROR); } @@ -320,7 +328,7 @@ spdy_stream_get_header(struct spdy_header_block *s, char *header, char **out) return (KORE_RESULT_OK); } - kore_debug("pair name %d bytes, value %d bytes", nlen, vlen); + kore_debug("pair name %u bytes, value %u bytes", nlen, vlen); p += nlen + vlen + 8; } @@ -333,7 +341,7 @@ spdy_session_teardown(struct connection *c, u_int8_t err) { u_int8_t d[8]; - kore_debug("spdy_session_teardown(%p, %d)", c, err); + kore_debug("spdy_session_teardown(%p, %u)", c, err); net_write32((u_int8_t *)&d[0], c->client_stream_id); net_write32((u_int8_t *)&d[4], err); @@ -363,11 +371,11 @@ spdy_update_wsize(struct connection *c, struct spdy_stream *s, u_int32_t len) kore_log(LOG_NOTICE, "A spdy stream was empty but not closed"); } - kore_debug("spdy_update_wsize(): stream %d, window size %d", + kore_debug("spdy_update_wsize(): stream %u, window size %d", s->stream_id, s->send_wsize); if (s->send_wsize <= 0) { - kore_debug("window size <= 0 for stream %d", s->stream_id); + kore_debug("window size <= 0 for stream %u", s->stream_id); c->flags &= ~CONN_WRITE_POSSIBLE; c->flags |= CONN_WRITE_BLOCK; @@ -397,27 +405,30 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb) syn.slot = net_read16(nb->buf + 16) & 0x7; kore_debug("spdy_ctrl_frame_syn_stream()"); - kore_debug("stream_id: %d", syn.stream_id); - kore_debug("length : %d", ctrl.length); + kore_debug("stream_id: %u", syn.stream_id); + kore_debug("length : %u", ctrl.length); + + if ((int)ctrl.length < 0) { + spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); + return (KORE_RESULT_OK); + } - /* XXX need to send protocol error. */ if ((syn.stream_id % 2) == 0 || syn.stream_id == 0) { - kore_debug("client sent incorrect id for SPDY_SYN_STREAM (%d)", + kore_debug("client sent incorrect id for SPDY_SYN_STREAM (%u)", syn.stream_id); spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); return (KORE_RESULT_OK); } - /* XXX need to send protocol error. */ if (syn.stream_id < c->client_stream_id) { - kore_debug("client sent incorrect id SPDY_SYN_STREAM (%d < %d)", + kore_debug("client sent incorrect id SPDY_SYN_STREAM (%u < %u)", syn.stream_id, c->client_stream_id); spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); return (KORE_RESULT_OK); } if ((s = spdy_stream_lookup(c, syn.stream_id)) != NULL) { - kore_debug("duplicate SPDY_SYN_STREAM (%d)", syn.stream_id); + kore_debug("duplicate SPDY_SYN_STREAM (%u)", syn.stream_id); spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); return (KORE_RESULT_OK); } @@ -433,7 +444,7 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb) s->hblock = spdy_header_block_create(SPDY_HBLOCK_DELAYED_ALLOC); src = (nb->buf + SPDY_FRAME_SIZE + SPDY_SYNFRAME_SIZE); - kore_debug("compressed headers are %d bytes long", ctrl.length - 10); + kore_debug("compressed headers are %u bytes long", ctrl.length - 10); if (!spdy_zlib_inflate(c, src, (ctrl.length - SPDY_SYNFRAME_SIZE), &(s->hblock->header_block), &(s->hblock->header_block_len))) { kore_mem_free(s->hblock->header_block); @@ -444,7 +455,15 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb) } s->hblock->header_pairs = net_read32(s->hblock->header_block); - kore_debug("got %d headers", s->hblock->header_pairs); + if ((int)s->hblock->header_pairs < 0) { + kore_mem_free(s->hblock->header_block); + kore_mem_free(s->hblock); + kore_mem_free(s); + spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); + return (KORE_RESULT_OK); + } + + kore_debug("got %u headers", s->hblock->header_pairs); path = NULL; host = NULL; @@ -493,7 +512,7 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb) c->client_stream_id = s->stream_id; TAILQ_INSERT_TAIL(&(c->spdy_streams), s, list); - kore_debug("SPDY_SYN_STREAM: %d:%d:%d", s->stream_id, + kore_debug("SPDY_SYN_STREAM: %u:%u:%u", s->stream_id, s->flags, s->prio); return (KORE_RESULT_OK); @@ -508,12 +527,12 @@ spdy_ctrl_frame_rst_stream(struct netbuf *nb) stream_id = net_read32(nb->buf + SPDY_FRAME_SIZE); if ((stream_id % 2) == 0) { - kore_debug("received RST for non-client stream %d", stream_id); + kore_debug("received RST for non-client stream %u", stream_id); return (KORE_RESULT_ERROR); } if ((s = spdy_stream_lookup(c, stream_id)) == NULL) { - kore_debug("received RST for unknown stream %d", stream_id); + kore_debug("received RST for unknown stream %u", stream_id); return (KORE_RESULT_ERROR); } @@ -530,11 +549,16 @@ spdy_ctrl_frame_settings(struct netbuf *nb) struct connection *c = (struct connection *)nb->owner; ecount = net_read32(nb->buf + SPDY_FRAME_SIZE); - kore_debug("SPDY_SETTINGS: %d settings present", ecount); - length = net_read32(nb->buf + 4) & 0xffffff; + if ((int)ecount < 0 || (int)length < 0) { + spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); + return (KORE_RESULT_OK); + } + + kore_debug("SPDY_SETTINGS: %u settings present", ecount); + if (length != ((ecount * 8) + 4)) { - kore_debug("ecount is not correct (%d != %d)", length, + kore_debug("ecount is not correct (%u != %u)", length, (ecount * 8) + 4); spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); return (KORE_RESULT_OK); @@ -545,12 +569,17 @@ spdy_ctrl_frame_settings(struct netbuf *nb) id = net_read32(buf) & 0xffffff; val = net_read32(buf + 4); + if ((int)val < 0) { + buf += 8; + continue; + } + switch (id) { case SETTINGS_INITIAL_WINDOW_SIZE: c->wsize_initial = val; break; default: - kore_debug("no handling for setting %d:%d", id, val); + kore_debug("no handling for setting %u:%u", id, val); break; } @@ -567,11 +596,11 @@ spdy_ctrl_frame_ping(struct netbuf *nb) struct connection *c = (struct connection *)nb->owner; id = ntohl(*(u_int32_t *)(nb->buf + SPDY_FRAME_SIZE)); - kore_debug("SPDY_PING: %d", id); + kore_debug("SPDY_PING: %u", id); /* XXX todo - check if we sent the ping. */ if ((id % 2) == 0) { - kore_debug("received malformed client PING (%d)", id); + kore_debug("received malformed client PING (%u)", id); spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); return (KORE_RESULT_OK); } @@ -592,12 +621,12 @@ spdy_ctrl_frame_window(struct netbuf *nb) if ((s = spdy_stream_lookup(c, stream_id)) == NULL) { kore_debug("received WINDOW_UPDATE for nonexistant stream"); - kore_debug("stream_id: %d", stream_id); + kore_debug("stream_id: %u", stream_id); spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); return (KORE_RESULT_OK); } - kore_debug("SPDY_WINDOW_UPDATE: %d:%d", stream_id, window_size); + kore_debug("SPDY_WINDOW_UPDATE: %u:%u", stream_id, window_size); s->send_wsize += window_size; if (s->send_wsize > 0 && c->flags & CONN_WRITE_BLOCK) { c->flags &= ~CONN_WRITE_BLOCK; @@ -606,7 +635,7 @@ spdy_ctrl_frame_window(struct netbuf *nb) kore_connection_stop_idletimer(c); c->idle_timer.length = spdy_idle_time; - kore_debug("can now send again (%d wsize)", s->send_wsize); + kore_debug("can now send again (%u wsize)", s->send_wsize); return (net_send_flush(c)); } @@ -626,9 +655,12 @@ spdy_data_frame_recv(struct netbuf *nb) data.stream_id = net_read32(nb->buf) & ~(1 << 31); data.flags = *(u_int8_t *)(nb->buf + 4); data.length = net_read32(nb->buf + 4) & 0xffffff; - kore_debug("SPDY_SESSION_DATA: %d:%d:%d", data.stream_id, + kore_debug("SPDY_SESSION_DATA: %u:%u:%u", data.stream_id, data.flags, data.length); + if ((int)data.length < 0) + return (KORE_RESULT_ERROR); + if ((s = spdy_stream_lookup(c, data.stream_id)) == NULL) { kore_debug("session data for non-existant stream"); /* stream error */