Stricter realpath checks

This commit is contained in:
cpq 2021-02-11 15:03:22 +00:00
parent ae5f6c0920
commit d5a1d5a5e8
5 changed files with 21 additions and 15 deletions

View File

@ -1090,11 +1090,11 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
char t1[MG_PATH_MAX], t2[sizeof(t1)]; char t1[MG_PATH_MAX], t2[sizeof(t1)];
t1[0] = t2[0] = '\0'; t1[0] = t2[0] = '\0';
if (realpath(opts->root_dir, t1) == NULL) if (realpath(opts->root_dir, t1) == NULL) {
LOG(LL_ERROR, ("realpath(%s): %d", opts->root_dir, errno)); LOG(LL_ERROR, ("realpath(%s): %d", opts->root_dir, errno));
mg_http_reply(c, 400, "", "Bad web root [%s]\n", opts->root_dir);
if (!mg_is_dir(t1)) { } else if (!mg_is_dir(t1)) {
mg_http_reply(c, 400, "", "Bad web root [%s]\n", t1); mg_http_reply(c, 400, "", "Invalid web root [%s]\n", t1);
} else { } else {
// NOTE(lsm): Xilinx snprintf does not 0-terminate the detination for // NOTE(lsm): Xilinx snprintf does not 0-terminate the detination for
// the %.*s specifier, if the length is zero. Make sure hm->uri.len > 0 // the %.*s specifier, if the length is zero. Make sure hm->uri.len > 0
@ -1106,8 +1106,11 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
n2 = strlen(t1); n2 = strlen(t1);
while (n2 > 0 && t1[n2 - 1] == '/') t1[--n2] = 0; while (n2 > 0 && t1[n2 - 1] == '/') t1[--n2] = 0;
if (realpath(t1, t2) == NULL) if (realpath(t1, t2) == NULL) {
LOG(LL_ERROR, ("realpath(%s): %d", t1, errno)); LOG(LL_ERROR, ("realpath(%s): %d", t1, errno));
mg_http_reply(c, 400, "", "Error serving [%s]\n", t1);
return;
}
if (mg_is_dir(t2)) { if (mg_is_dir(t2)) {
strncat(t2, "/index.html", sizeof(t2) - strlen(t2) - 1); strncat(t2, "/index.html", sizeof(t2) - strlen(t2) - 1);
@ -1117,7 +1120,7 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
if (strlen(t2) < n1 || memcmp(t1, t2, n1) != 0) { if (strlen(t2) < n1 || memcmp(t1, t2, n1) != 0) {
// Requested file is located outside root directory, fail // Requested file is located outside root directory, fail
mg_http_reply(c, 404, "", "Not found %.*s\n", (int) hm->uri.len, mg_http_reply(c, 404, "", "Invalid URI [%.*s]\n", (int) hm->uri.len,
hm->uri.ptr); hm->uri.ptr);
} else { } else {
FILE *fp = mg_fopen(t2, "r"); FILE *fp = mg_fopen(t2, "r");

View File

@ -270,7 +270,7 @@ typedef int socklen_t;
#ifndef EWOULDBLOCK #ifndef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK
#endif #endif
#define realpath(a, b) _fullpath((b), (a), 512) #define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
#ifndef va_copy #ifndef va_copy
#ifdef __va_copy #ifdef __va_copy
#define va_copy __va_copy #define va_copy __va_copy

View File

@ -40,7 +40,7 @@ typedef int socklen_t;
#ifndef EWOULDBLOCK #ifndef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK
#endif #endif
#define realpath(a, b) _fullpath((b), (a), 512) #define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
#ifndef va_copy #ifndef va_copy
#ifdef __va_copy #ifdef __va_copy
#define va_copy __va_copy #define va_copy __va_copy

View File

@ -670,11 +670,11 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
char t1[MG_PATH_MAX], t2[sizeof(t1)]; char t1[MG_PATH_MAX], t2[sizeof(t1)];
t1[0] = t2[0] = '\0'; t1[0] = t2[0] = '\0';
if (realpath(opts->root_dir, t1) == NULL) if (realpath(opts->root_dir, t1) == NULL) {
LOG(LL_ERROR, ("realpath(%s): %d", opts->root_dir, errno)); LOG(LL_ERROR, ("realpath(%s): %d", opts->root_dir, errno));
mg_http_reply(c, 400, "", "Bad web root [%s]\n", opts->root_dir);
if (!mg_is_dir(t1)) { } else if (!mg_is_dir(t1)) {
mg_http_reply(c, 400, "", "Bad web root [%s]\n", t1); mg_http_reply(c, 400, "", "Invalid web root [%s]\n", t1);
} else { } else {
// NOTE(lsm): Xilinx snprintf does not 0-terminate the detination for // NOTE(lsm): Xilinx snprintf does not 0-terminate the detination for
// the %.*s specifier, if the length is zero. Make sure hm->uri.len > 0 // the %.*s specifier, if the length is zero. Make sure hm->uri.len > 0
@ -686,8 +686,11 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
n2 = strlen(t1); n2 = strlen(t1);
while (n2 > 0 && t1[n2 - 1] == '/') t1[--n2] = 0; while (n2 > 0 && t1[n2 - 1] == '/') t1[--n2] = 0;
if (realpath(t1, t2) == NULL) if (realpath(t1, t2) == NULL) {
LOG(LL_ERROR, ("realpath(%s): %d", t1, errno)); LOG(LL_ERROR, ("realpath(%s): %d", t1, errno));
mg_http_reply(c, 400, "", "Error serving [%s]\n", t1);
return;
}
if (mg_is_dir(t2)) { if (mg_is_dir(t2)) {
strncat(t2, "/index.html", sizeof(t2) - strlen(t2) - 1); strncat(t2, "/index.html", sizeof(t2) - strlen(t2) - 1);
@ -697,7 +700,7 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
if (strlen(t2) < n1 || memcmp(t1, t2, n1) != 0) { if (strlen(t2) < n1 || memcmp(t1, t2, n1) != 0) {
// Requested file is located outside root directory, fail // Requested file is located outside root directory, fail
mg_http_reply(c, 404, "", "Not found %.*s\n", (int) hm->uri.len, mg_http_reply(c, 404, "", "Invalid URI [%.*s]\n", (int) hm->uri.len,
hm->uri.ptr); hm->uri.ptr);
} else { } else {
FILE *fp = mg_fopen(t2, "r"); FILE *fp = mg_fopen(t2, "r");

View File

@ -496,7 +496,7 @@ static void test_http_server(void) {
ASSERT(fetch(&mgr, buf, url, "GET /badroot HTTP/1.0\r\n\n") == 400); ASSERT(fetch(&mgr, buf, url, "GET /badroot HTTP/1.0\r\n\n") == 400);
#if MG_ARCH == MG_ARCH_WIN32 #if MG_ARCH == MG_ARCH_WIN32
ASSERT(cmpbody(buf, "Bad web root [Z:\\BAAADDD!]\n") == 0); ASSERT(cmpbody(buf, "Invalid web root [Z:\\BAAADDD!]\n") == 0);
#else #else
// LOG(LL_INFO, ("--> [%s]", buf)); // LOG(LL_INFO, ("--> [%s]", buf));
ASSERT(cmpbody(buf, "Bad web root [/BAAADDD!]\n") == 0); ASSERT(cmpbody(buf, "Bad web root [/BAAADDD!]\n") == 0);