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 <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2020-02-10 18:19:34 +01:00 committed by John Crispin
parent 57dd0ca59b
commit 39087eba18
2 changed files with 98 additions and 46 deletions

View File

@ -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

View File

@ -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;
memset(buf, 0, sizeof(buf));
var = getenv("CONTENT_LENGTH");
if ((len = read(0, buf, sizeof(buf) - 1)) > 0)
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; )
{
for (p = buf, i = 0; i <= len; i++)
{
if (buf[i] == '=')
{
buf[i] = 0;
rlen = read(0, postbuf + len, content_length - len);
for (field = 0; field < (n_fields * 2); field += 2)
if (rlen <= 0)
break;
len += rlen;
}
if (len < content_length)
{
free(postbuf);
return NULL;
}
for (p = postbuf, i = 0; i <= len; i++)
{
if (postbuf[i] == '=')
{
postbuf[i] = 0;
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");