unpack: prevent ability to bypass the byte limit
By passing an empty file with a declared negative size, a hostile VM can decrease the total bytes counter, while not have do supply a huge amount of data, thus disabing the byte size check, and potentially filling the target filesystem.
This commit is contained in:
parent
b95e80779e
commit
9f3a74fd77
@ -8,6 +8,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
#include "libqubes-rpc-filecopy.h"
|
#include "libqubes-rpc-filecopy.h"
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
|
|
||||||
@ -18,8 +19,18 @@ long long total_bytes = 0;
|
|||||||
long long total_files = 0;
|
long long total_files = 0;
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
|
|
||||||
|
void do_exit(int code, const char *last_filename)
|
||||||
|
{
|
||||||
|
close(0);
|
||||||
|
send_status_and_crc(code, last_filename);
|
||||||
|
exit(code);
|
||||||
|
}
|
||||||
|
|
||||||
void set_size_limit(long long new_bytes_limit, long long new_files_limit)
|
void set_size_limit(long long new_bytes_limit, long long new_files_limit)
|
||||||
{
|
{
|
||||||
|
if (new_bytes_limit < 0 || new_files_limit < 0) {
|
||||||
|
do_exit(EINVAL, "");
|
||||||
|
}
|
||||||
bytes_limit = new_bytes_limit;
|
bytes_limit = new_bytes_limit;
|
||||||
files_limit = new_files_limit;
|
files_limit = new_files_limit;
|
||||||
}
|
}
|
||||||
@ -58,13 +69,6 @@ void send_status_and_crc(int code, const char *last_filename) {
|
|||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_exit(int code, const char *last_filename)
|
|
||||||
{
|
|
||||||
close(0);
|
|
||||||
send_status_and_crc(code, last_filename);
|
|
||||||
exit(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fix_times_and_perms(struct file_header *untrusted_hdr,
|
void fix_times_and_perms(struct file_header *untrusted_hdr,
|
||||||
const char *untrusted_name)
|
const char *untrusted_name)
|
||||||
{
|
{
|
||||||
@ -88,9 +92,12 @@ 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 */
|
int fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700); /* safe because of chroot */
|
||||||
if (fdout < 0)
|
if (fdout < 0)
|
||||||
do_exit(errno, untrusted_name);
|
do_exit(errno, untrusted_name);
|
||||||
total_bytes += untrusted_hdr->filelen;
|
/* sizes are signed elsewhere */
|
||||||
if (bytes_limit && total_bytes > bytes_limit)
|
if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit))
|
||||||
do_exit(EDQUOT, untrusted_name);
|
do_exit(EDQUOT, untrusted_name);
|
||||||
|
if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen)
|
||||||
|
do_exit(EDQUOT, untrusted_name);
|
||||||
|
total_bytes += untrusted_hdr->filelen;
|
||||||
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
|
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
|
||||||
if (ret != COPY_FILE_OK) {
|
if (ret != COPY_FILE_OK) {
|
||||||
if (ret == COPY_FILE_READ_EOF
|
if (ret == COPY_FILE_READ_EOF
|
||||||
|
Loading…
Reference in New Issue
Block a user