aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/csource/linux_common.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-03-28 14:42:02 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-03-30 19:51:27 +0200
commit7c923cf8d45b650c4251503c11e74653779c74c4 (patch)
tree4ca1b65085c4fec4c2766fe558cdf69c8aaa9457 /pkg/csource/linux_common.go
parentd47f0ed6854fcc09c5db820d4e3aed72a6074841 (diff)
sys/linux: add support for mounting filesystem images
Diffstat (limited to 'pkg/csource/linux_common.go')
-rw-r--r--pkg/csource/linux_common.go132
1 files changed, 130 insertions, 2 deletions
diff --git a/pkg/csource/linux_common.go b/pkg/csource/linux_common.go
index 250b366d4..c9c8e871e 100644
--- a/pkg/csource/linux_common.go
+++ b/pkg/csource/linux_common.go
@@ -135,6 +135,16 @@ var commonHeaderLinux = `
#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
#include <sys/mount.h>
#endif
+#if defined(SYZ_EXECUTOR) || defined(__NR_syz_mount_image)
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/loop.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
defined(SYZ_USE_TMP_DIR) || defined(SYZ_HANDLE_SEGV) || defined(SYZ_TUN_ENABLE) || \
@@ -331,6 +341,11 @@ static uint16 csum_inet_digest(struct csum_inet* csum)
}
#endif
+#if defined(SYZ_EXECUTOR)
+struct thread_t;
+void cover_reset(thread_t* th);
+#endif
+
#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV)
static __thread int skip_segv;
static __thread jmp_buf segv_env;
@@ -906,6 +921,107 @@ static uintptr_t syz_genetlink_get_family_id(uintptr_t name)
}
#endif
+#if defined(SYZ_EXECUTOR) || defined(__NR_syz_mount_image)
+extern unsigned long long procid;
+
+struct fs_image_segment {
+ void* data;
+ uintptr_t size;
+ uintptr_t offset;
+};
+
+#define IMAGE_MAX_SEGMENTS 4096
+#define IMAGE_MAX_SIZE (32 << 20)
+
+#ifndef SYS_memfd_create
+#if defined(__i386__)
+#define SYS_memfd_create 356
+#elif defined(__x86_64__)
+#define SYS_memfd_create 319
+#elif defined(__arm__)
+#define SYS_memfd_create 385
+#elif defined(__aarch64__)
+#define SYS_memfd_create 279
+#elif defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__)
+#define SYS_memfd_create 360
+#endif
+#endif
+
+static uintptr_t syz_mount_image(uintptr_t fs, uintptr_t dir, uintptr_t size, uintptr_t nsegs, uintptr_t segments, uintptr_t flags, uintptr_t opts)
+{
+ char loopname[64];
+ int loopfd, err = 0, res = -1;
+ uintptr_t i;
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+
+ if (nsegs > IMAGE_MAX_SEGMENTS)
+ nsegs = IMAGE_MAX_SEGMENTS;
+ for (i = 0; i < nsegs; i++) {
+ if (segs[i].size > IMAGE_MAX_SIZE)
+ segs[i].size = IMAGE_MAX_SIZE;
+ segs[i].offset %= IMAGE_MAX_SIZE;
+ if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
+ segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
+ if (size < segs[i].offset + segs[i].offset)
+ size = segs[i].offset + segs[i].offset;
+ }
+ if (size > IMAGE_MAX_SIZE)
+ size = IMAGE_MAX_SIZE;
+ int memfd = syscall(SYS_memfd_create, "syz_mount_image", 0);
+ if (memfd == -1) {
+ err = errno;
+ goto error;
+ }
+ if (ftruncate(memfd, size)) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ for (i = 0; i < nsegs; i++) {
+ if (pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset) < 0) {
+ debug("syz_mount_image: pwrite[%lu] failed: %d\n", i, errno);
+ }
+ }
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
+ loopfd = open(loopname, O_RDWR);
+ if (loopfd == -1) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ if (errno != EBUSY) {
+ err = errno;
+ goto error_close_loop;
+ }
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ usleep(1000);
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ err = errno;
+ goto error_close_loop;
+ }
+ }
+ mkdir((char*)dir, 0777);
+ NONFAILING(if (strcmp((char*)fs, "iso9660") == 0) flags |= MS_RDONLY);
+ debug("syz_mount_image: size=%llu segs=%llu loop='%s' dir='%s' fs='%s' opts='%s'\n", (uint64)size, (uint64)nsegs, loopname, (char*)dir, (char*)fs, (char*)opts);
+#if defined(SYZ_EXECUTOR)
+ cover_reset(0);
+#endif
+ if (mount(loopname, (char*)dir, (char*)fs, flags, (char*)opts)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ res = 0;
+error_clear_loop:
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+error_close_loop:
+ close(loopfd);
+error_close_memfd:
+ close(memfd);
+error:
+ errno = err;
+ return res;
+}
+#endif
+
#if defined(SYZ_EXECUTOR) || defined(__NR_syz_kvm_setup_cpu)
#if defined(__x86_64__)
@@ -1962,7 +2078,7 @@ static void sandbox_common()
setrlimit(RLIMIT_AS, &rlim);
rlim.rlim_cur = rlim.rlim_max = 8 << 20;
setrlimit(RLIMIT_MEMLOCK, &rlim);
- rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
setrlimit(RLIMIT_FSIZE, &rlim);
rlim.rlim_cur = rlim.rlim_max = 1 << 20;
setrlimit(RLIMIT_STACK, &rlim);
@@ -2574,6 +2690,9 @@ static void remove_dir(const char* dir)
struct dirent* ep;
int iter = 0;
retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ debug("umount(%s)\n", dir);
+ }
dp = opendir(dir);
if (dp == NULL) {
if (errno == EMFILE) {
@@ -2730,6 +2849,15 @@ static void loop()
if (mkdir(cwdbuf, 0777))
fail("failed to mkdir");
#endif
+#if defined(SYZ_EXECUTOR) || defined(__NR_syz_mount_fs) || defined(__NR_syz_mount_image) || defined(__NR_syz_read_part_table)
+ char buf[64];
+ snprintf(buf, sizeof(buf), "/dev/loop%llu", procid);
+ int loopfd = open(buf, O_RDWR);
+ if (loopfd != -1) {
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ close(loopfd);
+ }
+#endif
#if defined(SYZ_EXECUTOR)
receive_execute(false);
#endif
@@ -2792,7 +2920,7 @@ static void loop()
executed_calls = now_executed;
last_executed = now;
}
- if ((now - start < 3 * 1000) && (now - last_executed < 500))
+ if ((now - start < 3 * 1000) && (now - start < 1000 || now - last_executed < 500))
continue;
#else
if (current_time_ms() - start < 3 * 1000)