libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

commit 75f0be5f084c39e6596c4f1ead827d30509ab60f
parent 1b215e49d37329b6c70c72d1b0518fa7fcb112e5
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Sat, 27 Jun 2026 20:19:35 +0200

Added checks for size overflows in response header building

Diffstat:
Msrc/mhd2/stream_process_reply.c | 55++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 46 insertions(+), 9 deletions(-)

diff --git a/src/mhd2/stream_process_reply.c b/src/mhd2/stream_process_reply.c @@ -54,6 +54,7 @@ #include "mhd_assert.h" #include "mhd_unreachable.h" +#include "mhd_predict.h" #include <string.h> #ifdef HAVE_TIME_H @@ -519,6 +520,8 @@ buffer_append (char *buf, size_t append_size) { mhd_assert (NULL != buf); /* Mute static analyzer */ + if (mhd_COND_HARDLY_EVER (*ppos + append_size < append_size)) /* Check for overflow */ + return false; if (buf_size < *ppos + append_size) return false; memcpy (buf + *ppos, append, append_size); @@ -585,7 +588,17 @@ add_user_headers (char *restrict buf, } /* Add user header */ - el_size = hdr->name.len + 2 + hdr->value.len + 2; + el_size = hdr->name.len + 2u; + if (mhd_COND_ALMOST_NEVER (2u > el_size)) /* Check for overflow */ + return false; + el_size += hdr->value.len; + if (mhd_COND_ALMOST_NEVER (hdr->value.len > el_size)) /* Check for overflow */ + return false; + el_size += 2u; + if (mhd_COND_ALMOST_NEVER (2u > el_size)) /* Check for overflow */ + return false; + if (mhd_COND_HARDLY_EVER (*ppos + el_size < el_size)) /* Check for overflow */ + return false; if (buf_size < *ppos + el_size) return false; memcpy (buf + *ppos, hdr->name.cstr, hdr->name.len); @@ -601,21 +614,31 @@ add_user_headers (char *restrict buf, if (add_close) { - el_size += mhd_SSTR_LEN ("close, "); + static const struct MHD_String cn_add = mhd_MSTR_INIT ("close, "); + el_size += cn_add.len; + if (mhd_COND_ALMOST_NEVER (cn_add.len > el_size)) /* Check for overflow */ + return false; + if (mhd_COND_HARDLY_EVER (initial_pos + el_size < el_size)) /* Check for overflow */ + return false; if (buf_size < initial_pos + el_size) return false; - memcpy (buf + *ppos, "close, ", - mhd_SSTR_LEN ("close, ")); - *ppos += mhd_SSTR_LEN ("close, "); + memcpy (buf + *ppos, cn_add.cstr, + cn_add.len); + *ppos += cn_add.len; } else { - el_size += mhd_SSTR_LEN ("Keep-Alive, "); + static const struct MHD_String cn_add = mhd_MSTR_INIT ("Keep-Alive, "); + el_size += cn_add.len; + if (mhd_COND_ALMOST_NEVER (cn_add.len > el_size)) /* Check for overflow */ + return false; + if (mhd_COND_HARDLY_EVER (initial_pos + el_size < el_size)) /* Check for overflow */ + return false; if (buf_size < initial_pos + el_size) return false; - memcpy (buf + *ppos, "Keep-Alive, ", - mhd_SSTR_LEN ("Keep-Alive, ")); - *ppos += mhd_SSTR_LEN ("Keep-Alive, "); + memcpy (buf + *ppos, cn_add.cstr, + cn_add.len); + *ppos += cn_add.len; } add_close = false; add_keep_alive = false; @@ -772,6 +795,8 @@ build_header_response_inn (struct MHD_Connection *restrict c) } /* The response code */ + if (mhd_COND_HARDLY_EVER (pos + 5 < 5)) /* Check for overflow */ + return false; if (buf_size < pos + 5) /* space + code + space */ return false; buf[pos++] = ' '; @@ -791,6 +816,8 @@ build_header_response_inn (struct MHD_Connection *restrict c) return false; } /* The linefeed */ + if (mhd_COND_HARDLY_EVER (pos + 2 < 2)) /* Check for overflow */ + return false; if (buf_size < pos + 2) return false; buf[pos++] = '\r'; @@ -802,6 +829,10 @@ build_header_response_inn (struct MHD_Connection *restrict c) if (0 != r->special_resp.spec_hdr_len) { mhd_assert (r->cfg.int_err_resp); + if (mhd_COND_HARDLY_EVER (r->special_resp.spec_hdr_len + 2 < 2)) /* Check for overflow */ + return false; + if (mhd_COND_HARDLY_EVER (pos + r->special_resp.spec_hdr_len + 2 < pos)) /* Check for overflow */ + return false; if (buf_size < pos + r->special_resp.spec_hdr_len + 2) return false; memcpy (buf + pos, @@ -819,6 +850,8 @@ build_header_response_inn (struct MHD_Connection *restrict c) (! c->daemon->req_cfg.suppress_date) ) { /* Additional byte for unused zero-termination */ + if (mhd_COND_HARDLY_EVER (pos + 38 < 38)) /* Check for overflow */ + return false; if (buf_size < pos + 38) return false; if (get_date_header (buf + pos)) @@ -916,6 +949,8 @@ build_header_response_inn (struct MHD_Connection *restrict c) return false; pos += el_size; + if (pos + 2 < 2) /* Check for overflow */ + return false; if (buf_size < pos + 2) return false; buf[pos++] = '\r'; @@ -932,6 +967,8 @@ build_header_response_inn (struct MHD_Connection *restrict c) } /* * Header termination * */ + if (mhd_COND_HARDLY_EVER (pos + 2 < 2)) /* Check for overflow */ + return false; if (buf_size < pos + 2) return false; buf[pos++] = '\r';