aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-12-26 09:39:22 +0100
committerDmitry Vyukov <dvyukov@google.com>2017-12-27 09:18:26 +0100
commitb7b7ac19fd9e2afbf5aea4db5e3f318576e6809f (patch)
treec43e8bbb312fc42016cd75526301ac9842ae70c9 /executor
parent6f03c356200becfa347b8abade66ac74f52c10c9 (diff)
executor: check format strings
I see a crash which says: #0: too much cover 0 (errno 0) while the code is: uint64_t n = ...; if (n >= kCoverSize) fail("#%d: too much cover %u", th->id, n); It seems that the high part of n is set, but we don't see it. Add printf format attribute to fail and friends and fix all similar cases. Caught a bunch of similar cases and a missing argument in: exitf("opendir(%s) failed due to NOFILE, exiting");
Diffstat (limited to 'executor')
-rw-r--r--executor/common.h18
-rw-r--r--executor/common_bsd.h6
-rw-r--r--executor/common_linux.h6
-rw-r--r--executor/executor.h36
-rw-r--r--executor/executor_linux.cc4
5 files changed, 36 insertions, 34 deletions
diff --git a/executor/common.h b/executor/common.h
index 78b752045..50348023f 100644
--- a/executor/common.h
+++ b/executor/common.h
@@ -28,18 +28,22 @@
// because some standard libraries contain "using ::exit;", but has different signature.
#define exit vsnprintf
#define _exit vsnprintf
-#endif
-#if defined(SYZ_EXECUTOR)
+// uint64_t is impossible to printf without using the clumsy and verbose "%" PRId64.
+// So we do the define and use "%lld" to printf uint64_t's.
+#define uint64_t unsigned long long
+
#if defined(__GNUC__)
#define SYSCALLAPI
#define NORETURN __attribute__((noreturn))
#define ALIGNED(N) __attribute__((aligned(N)))
+#define PRINTF __attribute__((format(printf, 1, 2)))
#else
// Assuming windows/cl.
#define SYSCALLAPI WINAPI
#define NORETURN __declspec(noreturn)
#define ALIGNED(N) __declspec(align(N))
+#define PRINTF
#endif
typedef long(SYSCALLAPI* syscall_t)(long, long, long, long, long, long, long, long, long);
@@ -53,7 +57,7 @@ struct call_t {
// Defined in generated syscalls_OS.h files.
extern call_t syscalls[];
extern unsigned syscall_count;
-#endif
+#endif // #if defined(SYZ_EXECUTOR)
#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \
@@ -71,7 +75,7 @@ const int kErrorStatus = 68;
defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \
defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(__NR_syz_kvm_setup_cpu)
// logical error (e.g. invalid input program), use as an assert() alernative
-NORETURN static void fail(const char* msg, ...)
+NORETURN PRINTF static void fail(const char* msg, ...)
{
int e = errno;
va_list args;
@@ -87,7 +91,7 @@ NORETURN static void fail(const char* msg, ...)
#if defined(SYZ_EXECUTOR)
// kernel error (e.g. wrong syscall return value)
-NORETURN static void error(const char* msg, ...)
+NORETURN PRINTF static void error(const char* msg, ...)
{
va_list args;
va_start(args, msg);
@@ -100,7 +104,7 @@ NORETURN static void error(const char* msg, ...)
#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR)) || defined(SYZ_FAULT_INJECTION)
// just exit (e.g. due to temporal ENOMEM error)
-NORETURN static void exitf(const char* msg, ...)
+NORETURN PRINTF static void exitf(const char* msg, ...)
{
int e = errno;
va_list args;
@@ -115,7 +119,7 @@ NORETURN static void exitf(const char* msg, ...)
#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG)
static int flag_debug;
-static void debug(const char* msg, ...)
+PRINTF static void debug(const char* msg, ...)
{
if (!flag_debug)
return;
diff --git a/executor/common_bsd.h b/executor/common_bsd.h
index a9c4933db..ff450f94a 100644
--- a/executor/common_bsd.h
+++ b/executor/common_bsd.h
@@ -51,13 +51,11 @@ static void segv_handler(int sig, siginfo_t* info, void* uctx)
const uintptr_t prog_start = 1 << 20;
const uintptr_t prog_end = 100 << 20;
if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) {
- debug("SIGSEGV on %p, skipping\n", addr);
+ debug("SIGSEGV on %p, skipping\n", (void*)addr);
_longjmp(segv_env, 1);
}
- debug("SIGSEGV on %p, exiting\n", addr);
+ debug("SIGSEGV on %p, exiting\n", (void*)addr);
doexit(sig);
- for (;;) {
- }
}
static void install_segv_handler()
diff --git a/executor/common_linux.h b/executor/common_linux.h
index 421486ed5..7f2247d12 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -150,10 +150,10 @@ static void segv_handler(int sig, siginfo_t* info, void* uctx)
const uintptr_t prog_start = 1 << 20;
const uintptr_t prog_end = 100 << 20;
if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) {
- debug("SIGSEGV on %p, skipping\n", addr);
+ debug("SIGSEGV on %p, skipping\n", (void*)addr);
_longjmp(segv_env, 1);
}
- debug("SIGSEGV on %p, exiting\n", addr);
+ debug("SIGSEGV on %p, exiting\n", (void*)addr);
doexit(sig);
}
@@ -891,7 +891,7 @@ retry:
// This happens when the test process casts prlimit(NOFILE) on us.
// Ideally we somehow prevent test processes from messing with parent processes.
// But full sandboxing is expensive, so let's ignore this error for now.
- exitf("opendir(%s) failed due to NOFILE, exiting");
+ exitf("opendir(%s) failed due to NOFILE, exiting", dir);
}
exitf("opendir(%s) failed", dir);
}
diff --git a/executor/executor.h b/executor/executor.h
index 84cefecf1..6fb32a76e 100644
--- a/executor/executor.h
+++ b/executor/executor.h
@@ -279,7 +279,7 @@ void receive_execute(bool need_prog)
break;
}
if (pos != req.prog_size)
- fail("bad input size %d, want %d", pos, req.prog_size);
+ fail("bad input size %lld, want %lld", pos, req.prog_size);
}
void reply_execute(int status)
@@ -333,16 +333,16 @@ retry:
break;
}
case arg_csum: {
- debug("checksum found at %llx\n", addr);
+ debug("checksum found at %p\n", addr);
uint64_t size = read_input(&input_pos);
char* csum_addr = addr;
uint64_t csum_kind = read_input(&input_pos);
switch (csum_kind) {
case arg_csum_inet: {
if (size != 2) {
- fail("inet checksum must be 2 bytes, not %lu", size);
+ fail("inet checksum must be 2 bytes, not %llu", size);
}
- debug("calculating checksum for %llx\n", csum_addr);
+ debug("calculating checksum for %p\n", csum_addr);
struct csum_inet csum;
csum_inet_init(&csum);
uint64_t chunks_num = read_input(&input_pos);
@@ -353,7 +353,7 @@ retry:
uint64_t chunk_size = read_input(&input_pos);
switch (chunk_kind) {
case arg_csum_chunk_data:
- debug("#%d: data chunk, addr: %llx, size: %llu\n", chunk, chunk_value, chunk_size);
+ debug("#%lld: data chunk, addr: %llx, size: %llu\n", chunk, chunk_value, chunk_size);
NONFAILING(csum_inet_update(&csum, (const uint8_t*)chunk_value, chunk_size));
break;
case arg_csum_chunk_const:
@@ -361,25 +361,25 @@ retry:
fail("bad checksum const chunk size %lld\n", chunk_size);
}
// Here we assume that const values come to us big endian.
- debug("#%d: const chunk, value: %llx, size: %llu\n", chunk, chunk_value, chunk_size);
+ debug("#%lld: const chunk, value: %llx, size: %llu\n", chunk, chunk_value, chunk_size);
csum_inet_update(&csum, (const uint8_t*)&chunk_value, chunk_size);
break;
default:
- fail("bad checksum chunk kind %lu", chunk_kind);
+ fail("bad checksum chunk kind %llu", chunk_kind);
}
}
int16_t csum_value = csum_inet_digest(&csum);
- debug("writing inet checksum %hx to %llx\n", csum_value, csum_addr);
+ debug("writing inet checksum %hx to %p\n", csum_value, csum_addr);
copyin(csum_addr, csum_value, 2, 0, 0);
break;
}
default:
- fail("bad checksum kind %lu", csum_kind);
+ fail("bad checksum kind %llu", csum_kind);
}
break;
}
default:
- fail("bad argument type %lu", typ);
+ fail("bad argument type %llu", typ);
}
continue;
}
@@ -393,11 +393,11 @@ retry:
// Normal syscall.
if (call_num >= syscall_count)
- fail("invalid command number %lu", call_num);
+ fail("invalid command number %llu", call_num);
uint64_t copyout_index = read_input(&input_pos);
uint64_t num_args = read_input(&input_pos);
if (num_args > kMaxArgs)
- fail("command has bad number of arguments %lu", num_args);
+ fail("command has bad number of arguments %llu", num_args);
uint64_t args[kMaxArgs] = {};
for (uint64_t i = 0; i < num_args; i++)
args[i] = read_arg(&input_pos);
@@ -489,7 +489,7 @@ void handle_completion(thread_t* th)
if (th->res != (long)-1) {
if (th->copyout_index != no_copyout) {
if (th->copyout_index >= kMaxCommands)
- fail("result idx %ld overflows kMaxCommands", th->copyout_index);
+ fail("result idx %lld overflows kMaxCommands", th->copyout_index);
results[th->copyout_index].executed = true;
results[th->copyout_index].val = th->res;
}
@@ -502,7 +502,7 @@ void handle_completion(thread_t* th)
uint64_t size = read_input(&th->copyout_pos);
uint64_t val = copyout(addr, size);
if (index >= kMaxCommands)
- fail("result idx %ld overflows kMaxCommands", index);
+ fail("result idx %lld overflows kMaxCommands", index);
results[index].executed = true;
results[index].val = val;
debug("copyout from %p\n", addr);
@@ -697,7 +697,7 @@ void copyin(char* addr, uint64_t val, uint64_t size, uint64_t bf_off, uint64_t b
STORE_BY_BITMASK(uint64_t, addr, val, bf_off, bf_len);
break;
default:
- fail("copyin: bad argument size %lu", size);
+ fail("copyin: bad argument size %llu", size);
});
}
@@ -718,7 +718,7 @@ uint64_t copyout(char* addr, uint64_t size)
res = *(uint64_t*)addr;
break;
default:
- fail("copyout: bad argument size %lu", size);
+ fail("copyout: bad argument size %llu", size);
});
return res;
}
@@ -736,7 +736,7 @@ uint64_t read_arg(uint64_t** input_posp)
return read_result(input_posp);
}
default:
- fail("bad argument type %lu", typ);
+ fail("bad argument type %llu", typ);
}
}
@@ -774,7 +774,7 @@ uint64_t read_result(uint64_t** input_posp)
uint64_t op_div = read_input(input_posp);
uint64_t op_add = read_input(input_posp);
if (idx >= kMaxCommands)
- fail("command refers to bad result %ld", idx);
+ fail("command refers to bad result %lld", idx);
uint64_t arg = default_value;
if (results[idx].executed) {
arg = results[idx].val;
diff --git a/executor/executor_linux.cc b/executor/executor_linux.cc
index 38ecf42f5..d66be92d2 100644
--- a/executor/executor_linux.cc
+++ b/executor/executor_linux.cc
@@ -262,9 +262,9 @@ uint64_t read_cover_size(thread_t* th)
if (!flag_cover)
return 0;
uint64_t n = __atomic_load_n(th->cover_size_ptr, __ATOMIC_RELAXED);
- debug("#%d: read cover size = %u\n", th->id, n);
+ debug("#%d: read cover size = %llu\n", th->id, n);
if (n >= kCoverSize)
- fail("#%d: too much cover %u", th->id, n);
+ fail("#%d: too much cover %llu", th->id, n);
return n;
}