From 3d5aa1436185913c2611deb5b2b51b65744f1e0f 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 --- Makefile | 2 +- src/main.c | 140 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 97 insertions(+), 45 deletions(-) diff --git a/Makefile b/Makefile index 27bdf73..c8e4164 100644 --- a/Makefile +++ b/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/src/main.c b/src/main.c index 7cf8d7b..6e9112c 100644 --- a/src/main.c +++ b/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