From 24857b29bc28753137e73565e8f9c26e67bf0770 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 22 Nov 2022 17:08:47 +0100 Subject: executor: don't pass uncompressed zlib size This will allow us to mutate the image size. Fixes #3527 --- executor/common_linux.h | 27 ++++++++++----------------- executor/common_test.h | 10 ++++++---- executor/common_zlib.h | 20 ++++++++++---------- 3 files changed, 26 insertions(+), 31 deletions(-) (limited to 'executor') diff --git a/executor/common_linux.h b/executor/common_linux.h index 40d2ad894..8ca854c9e 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -2897,7 +2897,7 @@ static long syz_genetlink_get_family_id(volatile long name, volatile long sock_a // creating and initializing the underlying file backing the loop device and // returns the fds to the file and device. // Returns 0 on success, -1 otherwise. -static int setup_loop_device(long unsigned size, long unsigned compressed_size, unsigned char* data, const char* loopname, int* memfd_p, int* loopfd_p) +static int setup_loop_device(unsigned char* data, unsigned long size, const char* loopname, int* memfd_p, int* loopfd_p) { int err = 0, loopfd = -1; int memfd = syscall(__NR_memfd_create, "syzkaller", 0); @@ -2905,12 +2905,7 @@ static int setup_loop_device(long unsigned size, long unsigned compressed_size, err = errno; goto error; } - if (ftruncate(memfd, size)) { - err = errno; - goto error_close_memfd; - } - - if (puff_zlib_to_file(data, compressed_size, memfd, size)) { + if (puff_zlib_to_file(data, size, memfd)) { err = errno; debug("setup_loop_device: could not decompress data: %d\n", errno); goto error_close_memfd; @@ -2949,15 +2944,15 @@ error: #endif #if SYZ_EXECUTOR || __NR_syz_read_part_table -// syz_read_part_table(size intptr, size_compressed len[img], img ptr[in, compressed_image]) -static long syz_read_part_table(volatile unsigned long size, volatile unsigned long compressed_size, volatile long image) +// syz_read_part_table(size len[img], img ptr[in, compressed_image]) +static long syz_read_part_table(volatile unsigned long size, volatile long image) { unsigned char* data = (unsigned char*)image; int err = 0, res = -1, loopfd = -1, memfd = -1; char loopname[64]; snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid); - if (setup_loop_device(size, compressed_size, data, loopname, &memfd, &loopfd) == -1) + if (setup_loop_device(data, size, loopname, &memfd, &loopfd) == -1) return -1; struct loop_info64 info; @@ -3003,25 +2998,23 @@ error_clear_loop: // syz_mount_image( // fs ptr[in, string[fs]], // dir ptr[in, filename], -// size intptr, -// size_compressed len[img], // flags flags[mount_flags], // opts ptr[in, fs_options], // chdir bool8, +// size len[img], // img ptr[in, compressed_image] // ) fd_dir static long syz_mount_image( volatile long fsarg, volatile long dir, - volatile unsigned long size, - volatile unsigned long compressed_size, volatile long flags, volatile long optsarg, volatile long change_dir, + volatile unsigned long size, volatile long image) { unsigned char* data = (unsigned char*)image; - int res = -1, err = 0, loopfd = -1, memfd = -1, need_loop_device = !!compressed_size; + int res = -1, err = 0, loopfd = -1, memfd = -1, need_loop_device = !!size; char* mount_opts = (char*)optsarg; char* target = (char*)dir; char* fs = (char*)fsarg; @@ -3033,7 +3026,7 @@ static long syz_mount_image( // filesystem image. memset(loopname, 0, sizeof(loopname)); snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid); - if (setup_loop_device(size, compressed_size, data, loopname, &memfd, &loopfd) == -1) + if (setup_loop_device(data, size, loopname, &memfd, &loopfd) == -1) return -1; source = loopname; } @@ -3058,7 +3051,7 @@ static long syz_mount_image( // and if two parallel executors mounts fs with the same uuid, second mount fails. strcat(opts, ",nouuid"); } - debug("syz_mount_image: size=%llu compressed_size=%llu loop='%s' dir='%s' fs='%s' flags=%llu opts='%s'\n", (uint64)size, (uint64)compressed_size, loopname, target, fs, (uint64)flags, opts); + debug("syz_mount_image: size=%llu loop='%s' dir='%s' fs='%s' flags=%llu opts='%s'\n", (uint64)size, loopname, target, fs, (uint64)flags, opts); #if SYZ_EXECUTOR cover_reset(0); #endif diff --git a/executor/common_test.h b/executor/common_test.h index 2ce410b36..6ef6ed82d 100644 --- a/executor/common_test.h +++ b/executor/common_test.h @@ -105,6 +105,7 @@ static long syz_compare_int(volatile long n, ...) #include "common_zlib.h" #include #include +#include // syz_compare_zlib(data ptr[in, array[int8]], size bytesize[data], zdata ptr[in, compressed_image], zsize bytesize[zdata]) static long syz_compare_zlib(volatile long data, volatile long size, volatile long zdata, volatile long zsize) @@ -112,14 +113,15 @@ static long syz_compare_zlib(volatile long data, volatile long size, volatile lo int fd = open("./uncompressed", O_RDWR | O_CREAT | O_EXCL, 0666); if (fd == -1) return -1; - if (ftruncate(fd, size)) + if (puff_zlib_to_file((unsigned char*)zdata, zsize, fd)) return -1; - if (puff_zlib_to_file((unsigned char*)zdata, zsize, fd, size)) + struct stat statbuf; + if (fstat(fd, &statbuf)) return -1; - void* uncompressed = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); + void* uncompressed = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (uncompressed == MAP_FAILED) return -1; - return syz_compare(data, size, (long)uncompressed, size); + return syz_compare(data, size, (long)uncompressed, statbuf.st_size); } #endif diff --git a/executor/common_zlib.h b/executor/common_zlib.h index e7e47e0fd..d3545ade2 100644 --- a/executor/common_zlib.h +++ b/executor/common_zlib.h @@ -493,11 +493,7 @@ static int puff( #include #define ZLIB_HEADER_WIDTH 2 // Two-byte zlib header width. -static int puff_zlib_to_file( - const unsigned char* source, - unsigned long sourcelen, - int dest_fd, - unsigned long destlen) +static int puff_zlib_to_file(const unsigned char* source, unsigned long sourcelen, int dest_fd) { // Ignore zlib header. if (sourcelen < ZLIB_HEADER_WIDTH) { @@ -507,20 +503,24 @@ static int puff_zlib_to_file( source += ZLIB_HEADER_WIDTH; sourcelen -= ZLIB_HEADER_WIDTH; - // Memory-map destination file dest_fd. - void* ret = mmap(0, destlen, PROT_WRITE | PROT_READ, MAP_SHARED, dest_fd, 0); + const unsigned long max_destlen = 132 << 20; + void* ret = mmap(0, max_destlen, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0); if (ret == MAP_FAILED) return -1; unsigned char* dest = (unsigned char*)ret; // Inflate source array to destination file. - unsigned long destlen_copy = destlen; // copy destlen as puff() may modify it - int err = puff(dest, &destlen_copy, source, &sourcelen); + unsigned long destlen = max_destlen; // copy destlen as puff() may modify it + int err = puff(dest, &destlen, source, &sourcelen); if (err) { + munmap(dest, max_destlen); errno = -err; return -1; } - + if (write(dest_fd, dest, destlen) != (ssize_t)destlen) { + munmap(dest, max_destlen); + return -1; + } // Unmap memory-mapped region return munmap(dest, destlen); } -- cgit mrf-deployment