From b8994f8bc38884622900b8b45ed1c4465fa36f62 Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Mon, 27 Oct 2025 16:43:44 -0300 Subject: [PATCH 1/3] Handle OOM situations in iobuf expansion --- mongoose.c | 238 +++++++++++++++++++++++++--------------------- mongoose.h | 4 +- src/iobuf.c | 10 +- src/iobuf.h | 4 +- src/net_builtin.c | 1 + src/sock.c | 27 +++--- src/ssi.c | 33 +++++-- src/tls_builtin.c | 167 ++++++++++++++++---------------- src/ws.c | 4 +- 9 files changed, 264 insertions(+), 224 deletions(-) diff --git a/mongoose.c b/mongoose.c index de6bf32b..5dd71c14 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2590,8 +2590,8 @@ static size_t roundup(size_t size, size_t align) { return align == 0 ? size : (size + align - 1) / align * align; } -int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { - int ok = 1; +bool mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { + bool ok = true; new_size = roundup(new_size, io->align); if (new_size == 0) { mg_bzero(io->buf, io->size); @@ -2610,14 +2610,14 @@ int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { io->size = new_size; io->len = len; } else { - ok = 0; + ok = false; MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size)); } } return ok; } -int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) { +bool mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) { io->buf = NULL; io->align = align; io->size = io->len = 0; @@ -6168,6 +6168,7 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) { res = tx_udp(ifp, s->mac, &c->loc, &c->rem, buf, len); } else { res = mg_iobuf_add(&c->send, c->send.len, buf, len); + // res == 0 means an OOM condition (iobuf couldn't resize), yet this is so far recoverable, let the caller decide } return res; } @@ -9523,6 +9524,8 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) { return n > 0; } else { return mg_iobuf_add(&c->send, c->send.len, buf, len); + // returning 0 means an OOM condition (iobuf couldn't resize), yet this is + // so far recoverable, let the caller decide } } @@ -9544,7 +9547,7 @@ static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) { #elif MG_ARCH == MG_ARCH_THREADX // NetxDuo fails to send large blocks of data to the non-blocking sockets (void) fd; - //fcntl(fd, F_SETFL, O_NONBLOCK); + // fcntl(fd, F_SETFL, O_NONBLOCK); #elif MG_ARCH == MG_ARCH_TIRTOS int val = 0; setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val)); @@ -9576,9 +9579,10 @@ void mg_multicast_add(struct mg_connection *c, char *ip) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr(ip); mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY); - setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)); -#endif // !Zephyr -#endif // !lwIP + setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, + sizeof(mreq)); +#endif // !Zephyr +#endif // !lwIP #endif } @@ -9696,9 +9700,9 @@ static void read_conn(struct mg_connection *c) { if (n == MG_IO_ERR || n == MG_IO_RESET) { // Windows, see #3031 if (c->rtls.len == 0 || m < 0) { // Close only when we have fully drained both rtls and TLS buffers - c->is_closing = 1; // or there's nothing we can do about it. - if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104 - } else { // see #2885 + c->is_closing = 1; // or there's nothing we can do about it. + if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104 + } else { // see #2885 // TLS buffer is capped to max record size, even though, there can // be more than one record, give TLS a chance to process them. } @@ -9748,7 +9752,7 @@ static void connect_conn(struct mg_connection *c) { mg_call(c, MG_EV_CONNECT, NULL); MG_EPOLL_MOD(c, 0); if (c->is_tls_hs) mg_tls_handshake(c); - if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() + if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() } else { mg_error(c, "socket error"); } @@ -9800,9 +9804,9 @@ void mg_connect_resolved(struct mg_connection *c) { rc = connect(FD(c), &usa.sa, slen); // Attempt to connect if (rc == 0) { // Success setlocaddr(FD(c), &c->loc); - mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user - if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() - } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake + mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user + if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() + } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem)); c->is_connecting = 1; } else { @@ -9862,7 +9866,7 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) { &c->rem, mg_print_ip_port, &c->loc)); mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_ACCEPT, NULL); - if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() + if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() } } @@ -10178,31 +10182,35 @@ static char *mg_ssi(const char *path, const char *root, int depth) { mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg); if (depth < MG_MAX_SSI_DEPTH && (data = mg_ssi(tmp, root, depth + 1)) != NULL) { - mg_iobuf_add(&b, b.len, data, strlen(data)); + size_t datalen = strlen(data); + size_t ret = mg_iobuf_add(&b, b.len, data, datalen); mg_free(data); + if (datalen > 0 && ret == 0) goto fail; } else { MG_ERROR(("%s: file=%s error or too deep", path, arg)); - } + } // TODO(): or OOM at recursive call } else if (sscanf(buf, "