Merge pull request #2718 from cesanta/pathissane

change mg_path_is_sane()
This commit is contained in:
Sergey Lyubka 2024-04-22 20:58:02 +01:00 committed by GitHub
commit 10029d6a8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 45 additions and 33 deletions

View File

@ -59,7 +59,7 @@ static void handle_uploads(struct mg_connection *c, int ev, void *ev_data) {
char fpath[MG_PATH_MAX];
snprintf(fpath, MG_PATH_MAX, "%s%c", s_upld_dir, MG_DIRSEP);
strncat(fpath, hm->uri.buf + 8, hm->uri.len - 8);
if (!mg_path_is_sane(fpath)) {
if (!mg_path_is_sane(mg_str(fpath))) {
mg_http_reply(c, 400, "", "Invalid path\n");
c->is_draining = 1; // Tell mongoose to close this connection
} else {

View File

@ -32,7 +32,7 @@ static void handle_uploads(struct mg_connection *c, int ev, void *ev_data) {
us->expected = hm->body.len; // Store number of bytes we expect
mg_iobuf_del(&c->recv, 0, hm->head.len); // Delete HTTP headers
c->pfn = NULL; // Silence HTTP protocol handler, we'll use MG_EV_READ
if (mg_path_is_sane(path)) {
if (mg_path_is_sane(mg_str(path))) {
fs->rm(path); // Delete file if it exists
us->fp = fs->op(path, MG_FS_WRITE); // Open file for writing
}

View File

@ -37,7 +37,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data) {
part.filename.buf, part.body.len));
mg_snprintf(path, sizeof(path), "%s/%.*s", s_upload_dir,
part.filename.len, part.filename.buf);
if (mg_path_is_sane(path)) {
if (mg_path_is_sane(mg_str(path))) {
mg_file_write(&mg_fs_posix, path, part.body.buf, part.body.len);
total_bytes += part.body.len;
num_files++;

View File

@ -2985,7 +2985,7 @@ static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
path_size - n, 0);
}
path[path_size - 1] = '\0'; // Double-check
if (!mg_path_is_sane(path)) {
if (!mg_path_is_sane(mg_str_n(path, path_size))) {
mg_http_reply(c, 400, "", "Invalid path");
return -1;
}
@ -3143,7 +3143,7 @@ long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
} else if (file[0] == '\0') {
mg_http_reply(c, 400, "", "file required");
res = -1;
} else if (mg_path_is_sane(file) == false) {
} else if (mg_path_is_sane(mg_str(file)) == false) {
mg_http_reply(c, 400, "", "%s: invalid file", file);
res = -2;
} else if (offset < 0) {
@ -8125,11 +8125,12 @@ void mg_unhex(const char *buf, size_t len, unsigned char *to) {
}
}
bool mg_path_is_sane(const char *path) {
const char *s = path;
if (path[0] == '.' && path[1] == '.') return false; // Starts with ..
for (; s[0] != '\0'; s++) {
if (s[0] == '/' || s[0] == '\\') { // Subdir?
bool mg_path_is_sane(const struct mg_str path) {
const char *s = path.buf;
size_t n = path.len;
if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with ..
for (; s[0] != '\0' && n > 0; s++, n--) {
if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir?
if (s[1] == '.' && s[2] == '.') return false; // Starts with ..
}
}

View File

@ -872,7 +872,7 @@ bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char delim);
char *mg_hex(const void *buf, size_t len, char *dst);
void mg_unhex(const char *buf, size_t len, unsigned char *to);
unsigned long mg_unhexn(const char *s, size_t len);
bool mg_path_is_sane(const char *path);
bool mg_path_is_sane(const struct mg_str path);
@ -2922,6 +2922,14 @@ struct mg_tcpip_driver_tm4c_data {
#endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500
#undef MG_ENABLE_TCPIP_DRIVER_INIT
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC
struct mg_tcpip_driver_xmc_data {

View File

@ -769,7 +769,7 @@ static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
path_size - n, 0);
}
path[path_size - 1] = '\0'; // Double-check
if (!mg_path_is_sane(path)) {
if (!mg_path_is_sane(mg_str_n(path, path_size))) {
mg_http_reply(c, 400, "", "Invalid path");
return -1;
}
@ -927,7 +927,7 @@ long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
} else if (file[0] == '\0') {
mg_http_reply(c, 400, "", "file required");
res = -1;
} else if (mg_path_is_sane(file) == false) {
} else if (mg_path_is_sane(mg_str(file)) == false) {
mg_http_reply(c, 400, "", "%s: invalid file", file);
res = -2;
} else if (offset < 0) {

View File

@ -173,11 +173,12 @@ void mg_unhex(const char *buf, size_t len, unsigned char *to) {
}
}
bool mg_path_is_sane(const char *path) {
const char *s = path;
if (path[0] == '.' && path[1] == '.') return false; // Starts with ..
for (; s[0] != '\0'; s++) {
if (s[0] == '/' || s[0] == '\\') { // Subdir?
bool mg_path_is_sane(const struct mg_str path) {
const char *s = path.buf;
size_t n = path.len;
if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with ..
for (; s[0] != '\0' && n > 0; s++, n--) {
if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir?
if (s[1] == '.' && s[2] == '.') return false; // Starts with ..
}
}

View File

@ -28,4 +28,4 @@ bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char delim);
char *mg_hex(const void *buf, size_t len, char *dst);
void mg_unhex(const char *buf, size_t len, unsigned char *to);
unsigned long mg_unhexn(const char *s, size_t len);
bool mg_path_is_sane(const char *path);
bool mg_path_is_sane(const struct mg_str path);

View File

@ -2107,20 +2107,22 @@ static void test_str(void) {
ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0]:3 7") == 0);
}
ASSERT(mg_path_is_sane(".") == true);
ASSERT(mg_path_is_sane("") == true);
ASSERT(mg_path_is_sane("a.b") == true);
ASSERT(mg_path_is_sane("a..b") == true);
ASSERT(mg_path_is_sane(".a") == true);
ASSERT(mg_path_is_sane(".a.") == true);
ASSERT(mg_path_is_sane("./") == true);
ASSERT(mg_path_is_sane("a..") == true);
ASSERT(mg_path_is_sane("././a..") == true);
ASSERT(mg_path_is_sane("..") == false);
ASSERT(mg_path_is_sane("../") == false);
ASSERT(mg_path_is_sane("./..") == false);
ASSERT(mg_path_is_sane("a/../") == false);
ASSERT(mg_path_is_sane("a/../b") == false);
ASSERT(mg_path_is_sane(mg_str(".")) == true);
ASSERT(mg_path_is_sane(mg_str("")) == true);
ASSERT(mg_path_is_sane(mg_str("a.b")) == true);
ASSERT(mg_path_is_sane(mg_str("a..b")) == true);
ASSERT(mg_path_is_sane(mg_str(".a")) == true);
ASSERT(mg_path_is_sane(mg_str(".a.")) == true);
ASSERT(mg_path_is_sane(mg_str("./")) == true);
ASSERT(mg_path_is_sane(mg_str("a..")) == true);
ASSERT(mg_path_is_sane(mg_str("././a..")) == true);
ASSERT(mg_path_is_sane(mg_str("..")) == false);
ASSERT(mg_path_is_sane(mg_str("../")) == false);
ASSERT(mg_path_is_sane(mg_str("./..")) == false);
ASSERT(mg_path_is_sane(mg_str("a/../")) == false);
ASSERT(mg_path_is_sane(mg_str("a/../b")) == false);
ASSERT(mg_path_is_sane(mg_str_n("a/..", 2)) == true);
ASSERT(mg_path_is_sane(mg_str_n("a/../b", 2)) == true);
}
static void fn1(struct mg_connection *c, int ev, void *ev_data) {