From 39087eba18011ca1e064c8e356ee33533be760db Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 10 Feb 2020 18:19:34 +0100 Subject: [PATCH] cgi-io: use dynamic memory for post decoding, support proc files Allocate dynamic buffer memory for decoding post data and allow post requsts up to 128KB compared to the previos 1KB limit. Also support downloading /proc and /sys files by falling back to chunked transfer encoding when the file size cannot be determined. Signed-off-by: Jo-Philipp Wich --- net/cgi-io/Makefile | 2 +- net/cgi-io/src/main.c | 140 +++++++++++++++++++++++++++++------------- 2 files changed, 97 insertions(+), 45 deletions(-) diff --git a/net/cgi-io/Makefile b/net/cgi-io/Makefile index 27bdf737fe..c8e4164ef9 100644 --- a/net/cgi-io/Makefile +++ b/net/cgi-io/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=cgi-io -PKG_RELEASE:=16 +PKG_RELEASE:=17 PKG_LICENSE:=GPL-2.0-or-later diff --git a/net/cgi-io/src/main.c b/net/cgi-io/src/main.c index 7cf8d7b23d..6e9112c0f9 100644 --- a/net/cgi-io/src/main.c +++ b/net/cgi-io/src/main.c @@ -38,6 +38,7 @@ #include "multipart_parser.h" #define READ_BLOCK 4096 +#define POST_LIMIT 131072 enum part { PART_UNKNOWN, @@ -223,55 +224,86 @@ urldecode(char *buf) return true; } -static bool +static char * postdecode(char **fields, int n_fields) { - char *p; const char *var; - static char buf[1024]; - int i, len, field, found = 0; + char *p, *postbuf; + int i, field, found = 0; + ssize_t len = 0, rlen = 0, content_length = 0; var = getenv("CONTENT_TYPE"); if (!var || strncmp(var, "application/x-www-form-urlencoded", 33)) - return false; + return NULL; + + var = getenv("CONTENT_LENGTH"); + + if (!var) + return NULL; + + content_length = strtol(var, &p, 10); + + if (p == var || content_length <= 0 || content_length >= POST_LIMIT) + return NULL; + + postbuf = calloc(1, content_length + 1); + + if (postbuf == NULL) + return NULL; + + for (len = 0; len < content_length; ) + { + rlen = read(0, postbuf + len, content_length - len); + + if (rlen <= 0) + break; - memset(buf, 0, sizeof(buf)); + len += rlen; + } - if ((len = read(0, buf, sizeof(buf) - 1)) > 0) + if (len < content_length) { - for (p = buf, i = 0; i <= len; i++) + free(postbuf); + return NULL; + } + + for (p = postbuf, i = 0; i <= len; i++) + { + if (postbuf[i] == '=') { - if (buf[i] == '=') - { - buf[i] = 0; + postbuf[i] = 0; - for (field = 0; field < (n_fields * 2); field += 2) + for (field = 0; field < (n_fields * 2); field += 2) + { + if (!strcmp(p, fields[field])) { - if (!strcmp(p, fields[field])) - { - fields[field + 1] = buf + i + 1; - found++; - } + fields[field + 1] = postbuf + i + 1; + found++; } } - else if (buf[i] == '&' || buf[i] == '\0') - { - buf[i] = 0; + } + else if (postbuf[i] == '&' || postbuf[i] == '\0') + { + postbuf[i] = 0; - if (found >= n_fields) - break; + if (found >= n_fields) + break; - p = buf + i + 1; - } + p = postbuf + i + 1; } } for (field = 0; field < (n_fields * 2); field += 2) + { if (!urldecode(fields[field + 1])) - return false; + { + free(postbuf); + return NULL; + } + } - return (found >= n_fields); + return postbuf; } static char * @@ -658,6 +690,14 @@ main_upload(int argc, char *argv[]) return 0; } +static void +free_charp(char **ptr) +{ + free(*ptr); +} + +#define autochar __attribute__((__cleanup__(free_charp))) char + static int main_download(int argc, char **argv) { @@ -668,7 +708,7 @@ main_download(int argc, char **argv) struct stat s; int rfd; - postdecode(fields, 4); + autochar *post = postdecode(fields, 4); if (!fields[1] || !session_access(fields[1], "cgi-io", "download", "read")) return failure(403, 0, "Download permission denied"); @@ -706,29 +746,39 @@ main_download(int argc, char **argv) if (fields[5]) printf("Content-Disposition: attachment; filename=\"%s\"\r\n", fields[5]); - printf("Content-Length: %llu\r\n\r\n", size); - fflush(stdout); + if (size > 0) { + printf("Content-Length: %llu\r\n\r\n", size); + fflush(stdout); - while (size > 0) { - len = sendfile(1, rfd, NULL, size); + while (size > 0) { + len = sendfile(1, rfd, NULL, size); - if (len == -1) { - if (errno == ENOSYS || errno == EINVAL) { - while ((len = read(rfd, buf, sizeof(buf))) > 0) - fwrite(buf, len, 1, stdout); + if (len == -1) { + if (errno == ENOSYS || errno == EINVAL) { + while ((len = read(rfd, buf, sizeof(buf))) > 0) + fwrite(buf, len, 1, stdout); - fflush(stdout); - break; + fflush(stdout); + break; + } + + if (errno == EINTR || errno == EAGAIN) + continue; } - if (errno == EINTR || errno == EAGAIN) - continue; + if (len <= 0) + break; + + size -= len; } + } + else { + printf("\r\n"); - if (len <= 0) - break; + while ((len = read(rfd, buf, sizeof(buf))) > 0) + fwrite(buf, len, 1, stdout); - size -= len; + fflush(stdout); } close(rfd); @@ -749,7 +799,9 @@ main_backup(int argc, char **argv) char hostname[64] = { 0 }; char *fields[] = { "sessionid", NULL }; - if (!postdecode(fields, 1) || !session_access(fields[1], "cgi-io", "backup", "read")) + autochar *post = postdecode(fields, 1); + + if (!fields[1] || !session_access(fields[1], "cgi-io", "backup", "read")) return failure(403, 0, "Backup permission denied"); if (pipe(fds)) @@ -929,7 +981,7 @@ main_exec(int argc, char **argv) char *p, **args; pid_t pid; - postdecode(fields, 4); + autochar *post = postdecode(fields, 4); if (!fields[1] || !session_access(fields[1], "cgi-io", "exec", "read")) return failure(403, 0, "Exec permission denied"); -- 2.30.2