diff --git a/common/filecopy.h b/common/filecopy.h index d3576a9e..c51d68e6 100644 --- a/common/filecopy.h +++ b/common/filecopy.h @@ -29,3 +29,4 @@ enum { int copy_file(int outfd, int infd, long long size, unsigned long *crc32); char *copy_file_status_to_str(int status); +void set_size_limit(long long new_bytes_limit, long long new_files_limit); diff --git a/common/unpack.c b/common/unpack.c index 70cc8fb6..580095d0 100644 --- a/common/unpack.c +++ b/common/unpack.c @@ -11,10 +11,21 @@ #include "crc32.h" char untrusted_namebuf[MAX_PATH_LENGTH]; +long long bytes_limit = 0; +long long files_limit = 0; +long long total_bytes = 0; +long long total_files = 0; + void notify_progress(int p1, int p2) { } +void set_size_limit(long long new_bytes_limit, long long new_files_limit) +{ + bytes_limit = new_bytes_limit; + files_limit = new_files_limit; +} + unsigned long crc32_sum = 0; int read_all_with_crc(int fd, void *buf, int size) { int ret; @@ -56,6 +67,9 @@ void process_one_file_reg(struct file_header *untrusted_hdr, int fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700); /* safe because of chroot */ if (fdout < 0) do_exit(errno); + total_bytes += untrusted_hdr->filelen; + if (bytes_limit && total_bytes > bytes_limit) + do_exit(EDQUOT); ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum); if (ret != COPY_FILE_OK) { if (ret == COPY_FILE_READ_EOF @@ -140,6 +154,9 @@ void do_unpack(int fd) break; } process_one_file(&untrusted_hdr); + total_files++; + if (files_limit && total_files > files_limit) + do_exit(EDQUOT); } send_status_and_crc(); if (errno) diff --git a/dom0/aux-tools/qfile-dom0-unpacker.c b/dom0/aux-tools/qfile-dom0-unpacker.c index 8ad8261a..f9861aa6 100644 --- a/dom0/aux-tools/qfile-dom0-unpacker.c +++ b/dom0/aux-tools/qfile-dom0-unpacker.c @@ -12,6 +12,10 @@ #include #include #include "filecopy.h" + +#define DEFAULT_MAX_UPDATES_BYTES (2L<<30) +#define DEFAULT_MAX_UPDATES_FILES 2048 + int prepare_creds_return_uid(char *username) { struct passwd *pwd; @@ -50,12 +54,20 @@ int main(int argc, char ** argv) char *incoming_dir; int pipefds[2]; int uid; + char *var; + long long files_limit = DEFAULT_MAX_UPDATES_FILES; + long long bytes_limit = DEFAULT_MAX_UPDATES_BYTES; if (argc < 3) { fprintf(stderr, "Invalid parameters, usage: %s user dir\n", argv[0]); exit(1); } + if ((var=getenv("UPDATES_MAX_BYTES"))) + bytes_limit = atoll(var); + if ((var=getenv("UPDATES_MAX_FILES"))) + files_limit = atoll(var); + pipe(pipefds); uid = prepare_creds_return_uid(argv[1]); @@ -73,6 +85,7 @@ int main(int argc, char ** argv) gui_fatal("Error chroot to %s", incoming_dir); setuid(uid); close(pipefds[0]); + set_size_limit(bytes_limit, files_limit); do_unpack(pipefds[1]); exit(0); default:;