Skip to content

Commit 60c0d8d

Browse files
committed
Handle OOM situations in iobuf expansion
1 parent 1a0167e commit 60c0d8d

File tree

9 files changed

+252
-188
lines changed

9 files changed

+252
-188
lines changed

mongoose.c

Lines changed: 123 additions & 91 deletions
Large diffs are not rendered by default.

mongoose.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,8 +1488,8 @@ struct mg_iobuf {
14881488
size_t align; // Alignment during allocation
14891489
};
14901490

1491-
int mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
1492-
int mg_iobuf_resize(struct mg_iobuf *, size_t);
1491+
bool mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
1492+
bool mg_iobuf_resize(struct mg_iobuf *, size_t);
14931493
void mg_iobuf_free(struct mg_iobuf *);
14941494
size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
14951495
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);

src/iobuf.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
#include "arch.h"
21
#include "iobuf.h"
2+
#include "arch.h"
33
#include "log.h"
44
#include "util.h"
55

66
static size_t roundup(size_t size, size_t align) {
77
return align == 0 ? size : (size + align - 1) / align * align;
88
}
99

10-
int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
11-
int ok = 1;
10+
bool mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
11+
bool ok = true;
1212
new_size = roundup(new_size, io->align);
1313
if (new_size == 0) {
1414
mg_bzero(io->buf, io->size);
@@ -27,14 +27,14 @@ int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
2727
io->size = new_size;
2828
io->len = len;
2929
} else {
30-
ok = 0;
30+
ok = false;
3131
MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size));
3232
}
3333
}
3434
return ok;
3535
}
3636

37-
int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
37+
bool mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
3838
io->buf = NULL;
3939
io->align = align;
4040
io->size = io->len = 0;

src/iobuf.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ struct mg_iobuf {
99
size_t align; // Alignment during allocation
1010
};
1111

12-
int mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
13-
int mg_iobuf_resize(struct mg_iobuf *, size_t);
12+
bool mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
13+
bool mg_iobuf_resize(struct mg_iobuf *, size_t);
1414
void mg_iobuf_free(struct mg_iobuf *);
1515
size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
1616
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);

src/net_builtin.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,7 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
14591459
len);
14601460
} else {
14611461
res = mg_iobuf_add(&c->send, c->send.len, buf, len);
1462+
// res == 0 means an OOM condition (iobuf couldn't resize), yet this is so far recoverable, let the caller decide
14621463
}
14631464
return res;
14641465
}

src/sock.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
142142
return n > 0;
143143
} else {
144144
return mg_iobuf_add(&c->send, c->send.len, buf, len);
145+
// returning 0 means an OOM condition (iobuf couldn't resize), yet this is
146+
// so far recoverable, let the caller decide
145147
}
146148
}
147149

@@ -163,7 +165,7 @@ static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
163165
#elif MG_ARCH == MG_ARCH_THREADX
164166
// NetxDuo fails to send large blocks of data to the non-blocking sockets
165167
(void) fd;
166-
//fcntl(fd, F_SETFL, O_NONBLOCK);
168+
// fcntl(fd, F_SETFL, O_NONBLOCK);
167169
#elif MG_ARCH == MG_ARCH_TIRTOS
168170
int val = 0;
169171
setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
@@ -195,9 +197,10 @@ void mg_multicast_add(struct mg_connection *c, char *ip) {
195197
struct ip_mreq mreq;
196198
mreq.imr_multiaddr.s_addr = inet_addr(ip);
197199
mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY);
198-
setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
199-
#endif // !Zephyr
200-
#endif // !lwIP
200+
setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq,
201+
sizeof(mreq));
202+
#endif // !Zephyr
203+
#endif // !lwIP
201204
#endif
202205
}
203206

@@ -315,9 +318,9 @@ static void read_conn(struct mg_connection *c) {
315318
if (n == MG_IO_ERR || n == MG_IO_RESET) { // Windows, see #3031
316319
if (c->rtls.len == 0 || m < 0) {
317320
// Close only when we have fully drained both rtls and TLS buffers
318-
c->is_closing = 1; // or there's nothing we can do about it.
319-
if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104
320-
} else { // see #2885
321+
c->is_closing = 1; // or there's nothing we can do about it.
322+
if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104
323+
} else { // see #2885
321324
// TLS buffer is capped to max record size, even though, there can
322325
// be more than one record, give TLS a chance to process them.
323326
}
@@ -367,7 +370,7 @@ static void connect_conn(struct mg_connection *c) {
367370
mg_call(c, MG_EV_CONNECT, NULL);
368371
MG_EPOLL_MOD(c, 0);
369372
if (c->is_tls_hs) mg_tls_handshake(c);
370-
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
373+
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
371374
} else {
372375
mg_error(c, "socket error");
373376
}
@@ -419,9 +422,9 @@ void mg_connect_resolved(struct mg_connection *c) {
419422
rc = connect(FD(c), &usa.sa, slen); // Attempt to connect
420423
if (rc == 0) { // Success
421424
setlocaddr(FD(c), &c->loc);
422-
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
423-
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
424-
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
425+
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
426+
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
427+
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
425428
MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
426429
c->is_connecting = 1;
427430
} else {
@@ -481,7 +484,7 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
481484
&c->rem, mg_print_ip_port, &c->loc));
482485
mg_call(c, MG_EV_OPEN, NULL);
483486
mg_call(c, MG_EV_ACCEPT, NULL);
484-
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
487+
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
485488
}
486489
}
487490

src/ssi.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
#include "ssi.h"
12
#include "log.h"
23
#include "printf.h"
3-
#include "ssi.h"
44
#include "util.h"
55

66
#ifndef MG_MAX_SSI_DEPTH
@@ -31,31 +31,35 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
3131
mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
3232
if (depth < MG_MAX_SSI_DEPTH &&
3333
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
34-
mg_iobuf_add(&b, b.len, data, strlen(data));
34+
size_t datalen = strlen(data);
35+
size_t ret = mg_iobuf_add(&b, b.len, data, datalen);
3536
mg_free(data);
37+
if (datalen > 0 && ret == 0) goto fail;
3638
} else {
3739
MG_ERROR(("%s: file=%s error or too deep", path, arg));
38-
}
40+
} // TODO(): or OOM at recursive call
3941
} else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg) > 0) {
4042
char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data;
4143
mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
4244
if (depth < MG_MAX_SSI_DEPTH &&
4345
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
44-
mg_iobuf_add(&b, b.len, data, strlen(data));
46+
size_t datalen = strlen(data);
47+
size_t ret = mg_iobuf_add(&b, b.len, data, datalen);
4548
mg_free(data);
49+
if (datalen > 0 && ret == 0) goto fail;
4650
} else {
4751
MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
48-
}
52+
} // TODO(): or OOM at recursive call
4953
} else {
5054
// Unknown SSI tag
5155
MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf));
52-
mg_iobuf_add(&b, b.len, buf, len);
56+
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
5357
}
5458
intag = 0;
5559
len = 0;
5660
} else if (ch == '<') {
5761
intag = 1;
58-
if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
62+
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
5963
len = 0;
6064
buf[len++] = (char) (ch & 0xff);
6165
} else if (intag) {
@@ -69,24 +73,33 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
6973
} else {
7074
buf[len++] = (char) (ch & 0xff);
7175
if (len >= sizeof(buf)) {
72-
mg_iobuf_add(&b, b.len, buf, len);
76+
if (mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
7377
len = 0;
7478
}
7579
}
7680
}
77-
if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
78-
if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1); // nul-terminate
81+
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
82+
if (b.len > 0 && mg_iobuf_add(&b, b.len, "", 1) == 0) // nul-terminate
83+
goto fail;
7984
fclose(fp);
8085
}
8186
(void) depth;
8287
(void) root;
8388
return (char *) b.buf;
89+
90+
fail:
91+
fclose(fp);
92+
return NULL;
8493
}
8594

8695
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
8796
const char *fullpath) {
8897
const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
8998
char *data = mg_ssi(fullpath, root, 0);
99+
if (data == NULL) {
100+
mg_error(c, "OOM");
101+
return;
102+
}
90103
mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
91104
mg_free(data);
92105
}

0 commit comments

Comments
 (0)