diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-12-26 09:39:22 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-12-27 09:18:26 +0100 |
| commit | b7b7ac19fd9e2afbf5aea4db5e3f318576e6809f (patch) | |
| tree | c43e8bbb312fc42016cd75526301ac9842ae70c9 /executor | |
| parent | 6f03c356200becfa347b8abade66ac74f52c10c9 (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.h | 18 | ||||
| -rw-r--r-- | executor/common_bsd.h | 6 | ||||
| -rw-r--r-- | executor/common_linux.h | 6 | ||||
| -rw-r--r-- | executor/executor.h | 36 | ||||
| -rw-r--r-- | executor/executor_linux.cc | 4 |
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; } |
