Merge pull request #3776 from cesanta/embnul

reject embedded NULs in paths
This commit is contained in:
Sergio R. Caprile authored and GitHub committed 2026-11-12 15:42:18 -03:00
commit 0b888e8f3f
3 files changed
+17 -8

No files matched your search

+8 -4
View File
@@ -4906,11 +4906,15 @@ static bool uri2path(const char *r, struct mg_str uri, char *buf, size_t len) {
n = mg_snprintf(buf, len, "%.*s", (int) d.len, d.buf); n = mg_snprintf(buf, len, "%.*s", (int) d.len, d.buf);
if (len == 0 || n + 2 >= len) return false; // Path overflow if (len == 0 || n + 2 >= len) return false; // Path overflow
if (n > 0 && buf[n - 1] != '/') buf[n++] = '/', buf[n] = '\0'; // Add slash if (n > 0 && buf[n - 1] != '/') buf[n++] = '/', buf[n] = '\0'; // Add slash
if (mg_url_decode(uri.buf + u.len, uri.len - u.len, buf + n, len - n, 0) < 0) { {
return false; int dn;
size_t p = n;
dn = mg_url_decode(uri.buf + u.len, uri.len - u.len, buf + n, len - n, 0);
if (dn < 0) return false; // reject on malformed
buf[len - 1] = '\0'; // Double-check
n = strlen(buf);
if (n != p + (size_t) dn) return false; // reject on embedded NULs
} }
buf[len - 1] = '\0'; // Double-check
n = strlen(buf);
if (!mg_path_is_sane(mg_str_n(buf, n))) return false; if (!mg_path_is_sane(mg_str_n(buf, n))) return false;
while (n > 1 && buf[n - 1] == '/') buf[--n] = 0; // Trim trailing slashes while (n > 1 && buf[n - 1] == '/') buf[--n] = 0; // Trim trailing slashes
return true; return true;
+8 -4
View File
@@ -752,11 +752,15 @@ static bool uri2path(const char *r, struct mg_str uri, char *buf, size_t len) {
n = mg_snprintf(buf, len, "%.*s", (int) d.len, d.buf); n = mg_snprintf(buf, len, "%.*s", (int) d.len, d.buf);
if (len == 0 || n + 2 >= len) return false; // Path overflow if (len == 0 || n + 2 >= len) return false; // Path overflow
if (n > 0 && buf[n - 1] != '/') buf[n++] = '/', buf[n] = '\0'; // Add slash if (n > 0 && buf[n - 1] != '/') buf[n++] = '/', buf[n] = '\0'; // Add slash
if (mg_url_decode(uri.buf + u.len, uri.len - u.len, buf + n, len - n, 0) < 0) { {
return false; int dn;
size_t p = n;
dn = mg_url_decode(uri.buf + u.len, uri.len - u.len, buf + n, len - n, 0);
if (dn < 0) return false; // reject on malformed
buf[len - 1] = '\0'; // Double-check
n = strlen(buf);
if (n != p + (size_t) dn) return false; // reject on embedded NULs
} }
buf[len - 1] = '\0'; // Double-check
n = strlen(buf);
if (!mg_path_is_sane(mg_str_n(buf, n))) return false; if (!mg_path_is_sane(mg_str_n(buf, n))) return false;
while (n > 1 && buf[n - 1] == '/') buf[--n] = 0; // Trim trailing slashes while (n > 1 && buf[n - 1] == '/') buf[--n] = 0; // Trim trailing slashes
return true; return true;
+1
View File
@@ -1519,6 +1519,7 @@ static void test_http_404(void) {
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200); ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, "hello\n") == 0); ASSERT(cmpbody(buf, "hello\n") == 0);
ASSERT(fetch(&mgr, buf, url, "GET /a.txt%%00x HTTP/1.0\n\n") == 400);
ASSERT(fetch(&mgr, buf, url, "GET /a/a.txt HTTP/1.0\n\n") == 200); ASSERT(fetch(&mgr, buf, url, "GET /a/a.txt HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, "hello\n") == 0); ASSERT(cmpbody(buf, "hello\n") == 0);
ASSERT(fetch(&mgr, buf, url, "GET /unmapped HTTP/1.0\n\n") == 400); ASSERT(fetch(&mgr, buf, url, "GET /unmapped HTTP/1.0\n\n") == 400);