aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2021-02-21 12:32:11 +0100
committerDmitry Vyukov <dvyukov@google.com>2021-02-21 16:43:26 +0100
commita659b3f1dc889d5ab5ead017b877765b3d042379 (patch)
tree8df03976c96285623e94f39e7a44773170b0a9d8 /executor
parente894953c0c45c8a6d676292a81da90a615133b1c (diff)
pkg/report: detect executor failures
Currently all executor fail errors go into "lost connection" bucket. This is not very useful. First, there are different executor failures. Second, it's not possible to understand what failures happen how frequently. Third, there are not authentic lost connection. Create separate SYZFAIL: bugs for them. Update #573 Update #502 Update #318
Diffstat (limited to 'executor')
-rw-r--r--executor/android/android_seccomp.h7
-rw-r--r--executor/common_bsd.h17
-rw-r--r--executor/common_fuchsia.h3
-rw-r--r--executor/common_linux.h176
-rw-r--r--executor/common_usb_netbsd.h20
-rw-r--r--executor/cov_filter.h2
-rw-r--r--executor/executor.cc119
-rw-r--r--executor/executor_bsd.h2
-rw-r--r--executor/executor_fuchsia.h2
-rw-r--r--executor/executor_linux.h2
-rw-r--r--executor/style_test.go10
11 files changed, 183 insertions, 177 deletions
diff --git a/executor/android/android_seccomp.h b/executor/android/android_seccomp.h
index d8df52792..f3febac2c 100644
--- a/executor/android/android_seccomp.h
+++ b/executor/android/android_seccomp.h
@@ -46,7 +46,7 @@ typedef struct Filter_t {
static void push_back(Filter* filter_array, struct sock_filter filter)
{
if (filter_array->count == kFilterMaxSize)
- fail("can't add another syscall to seccomp filter: count %zu", filter_array->count);
+ failmsg("can't add another syscall to seccomp filter", "count=%zu", filter_array->count);
filter_array->data[filter_array->count++] = filter;
}
@@ -79,9 +79,8 @@ static void install_filter(const Filter* f)
(struct sock_filter*)&f->data[0],
};
// This assumes either the current process has CAP_SYS_ADMIN, or PR_SET_NO_NEW_PRIVS bit is set.
- if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
- fail("Could not set seccomp filter of size %zu", f->count);
- }
+ if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0)
+ failmsg("could not set seccomp filter", "size=%zu", f->count);
}
// Modified from the orignal Android code as we don't need dual arch support
diff --git a/executor/common_bsd.h b/executor/common_bsd.h
index 7ccd1053f..1bed0cf3c 100644
--- a/executor/common_bsd.h
+++ b/executor/common_bsd.h
@@ -33,7 +33,7 @@ static void setup_usb(void)
char path[1024];
snprintf(path, sizeof(path), "/dev/%s", ent->d_name);
if (chmod(path, 0666))
- fail("failed to chmod %s", path);
+ failmsg("failed to chmod vhci", "path=%s", path);
}
closedir(dir);
@@ -61,7 +61,7 @@ static int inject_fault(int nth)
en.mode = 0; // FAULT_MODE_NTH_ONESHOT
en.nth = nth + 2; // FAULT_NTH_MIN
if (ioctl(fd, FAULT_IOC_ENABLE, &en) != 0)
- fail("FAULT_IOC_ENABLE failed with nth=%d", nth);
+ failmsg("FAULT_IOC_ENABLE failed", "nth=%d", nth);
return fd;
}
@@ -149,7 +149,7 @@ static void vsnprintf_check(char* str, size_t size, const char* format, va_list
if (rv < 0)
fail("vsnprintf failed");
if ((size_t)rv >= size)
- fail("vsnprintf: string '%s...' doesn't fit into buffer", str);
+ failmsg("vsnprintf: string doesn't fit into buffer", "string='%s'", str);
}
static void snprintf_check(char* str, size_t size, const char* format, ...)
@@ -179,7 +179,7 @@ static void execute_command(bool panic, const char* format, ...)
int rv = system(command);
if (rv) {
if (panic)
- fail("command '%s' failed: %d", &command[0], rv);
+ failmsg("command failed", "command=%s: %d", &command[0], rv);
debug("command '%s': %d\n", &command[0], rv);
}
}
@@ -191,9 +191,8 @@ static void initialize_tun(int tun_id)
return;
#endif // SYZ_EXECUTOR
- if (tun_id < 0 || tun_id >= MAX_TUN) {
- fail("tun_id out of range %d", tun_id);
- }
+ if (tun_id < 0 || tun_id >= MAX_TUN)
+ failmsg("tun_id out of range", "tun_id=%d", tun_id);
char tun_device[sizeof(TUN_DEVICE)];
snprintf_check(tun_device, sizeof(tun_device), TUN_DEVICE, tun_id);
@@ -219,7 +218,7 @@ static void initialize_tun(int tun_id)
#endif
if (tunfd == -1) {
#if SYZ_EXECUTOR
- fail("tun: can't open %s", tun_device);
+ failmsg("tun: can't open device", "device=%s", tun_device);
#else
printf("tun: can't open %s: errno=%d\n", tun_device, errno);
return;
@@ -300,7 +299,7 @@ static int read_tun(char* data, int size)
if (rv < 0) {
if (errno == EAGAIN)
return -1;
- fail("tun: read failed with %d", rv);
+ fail("tun: read failed");
}
return rv;
}
diff --git a/executor/common_fuchsia.h b/executor/common_fuchsia.h
index 6576e83f0..607518178 100644
--- a/executor/common_fuchsia.h
+++ b/executor/common_fuchsia.h
@@ -119,7 +119,8 @@ static void install_segv_handler(void)
zx_status_t status;
zx_handle_t exception_channel;
if ((status = zx_task_create_exception_channel(zx_process_self(), 0, &exception_channel)) != ZX_OK)
- fail("zx_task_create_exception_channel failed: %s (%d)", zx_status_get_string(status), status);
+ failmsg("zx_task_create_exception_channel failed",
+ "status=%s (%d)", zx_status_get_string(status), status);
pthread_t th;
if (pthread_create(&th, 0, ex_handler, (void*)(long)exception_channel))
fail("pthread_create failed");
diff --git a/executor/common_linux.h b/executor/common_linux.h
index a6a117c5b..1d3500a57 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -186,7 +186,7 @@ static int netlink_send_ext(struct nlmsg* nlmsg, int sock,
ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0, (struct sockaddr*)&addr, sizeof(addr));
if (n != (ssize_t)hdr->nlmsg_len) {
if (dofail)
- fail("netlink_send_ext: short netlink write: %zd/%d", n, hdr->nlmsg_len);
+ failmsg("netlink_send_ext: short netlink write", "wrote=%zd, want=%d", n, hdr->nlmsg_len);
debug("netlink_send_ext: short netlink write: %zd/%d errno=%d\n", n, hdr->nlmsg_len, errno);
return -1;
}
@@ -195,14 +195,14 @@ static int netlink_send_ext(struct nlmsg* nlmsg, int sock,
*reply_len = 0;
if (n < 0) {
if (dofail)
- fail("netlink_send_ext: netlink read failed: %zd", n);
- debug("netlink_send_ext: netlink read failed: %zd errno=%d\n", n, errno);
+ fail("netlink_send_ext: netlink read failed");
+ debug("netlink_send_ext: netlink read failed: errno=%d\n", errno);
return -1;
}
if (n < (ssize_t)sizeof(struct nlmsghdr)) {
errno = EINVAL;
if (dofail)
- fail("netlink_send_ext: short netlink read: %zd", n);
+ failmsg("netlink_send_ext: short netlink read", "read=%zd", n);
debug("netlink_send_ext: short netlink read: %zd\n", n);
return -1;
}
@@ -215,14 +215,14 @@ static int netlink_send_ext(struct nlmsg* nlmsg, int sock,
if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) {
errno = EINVAL;
if (dofail)
- fail("netlink_send_ext: short netlink read: %zd", n);
+ failmsg("netlink_send_ext: short netlink read", "read=%zd", n);
debug("netlink_send_ext: short netlink read: %zd\n", n);
return -1;
}
if (hdr->nlmsg_type != NLMSG_ERROR) {
errno = EINVAL;
if (dofail)
- fail("netlink_send_ext: short netlink ack: %d", hdr->nlmsg_type);
+ failmsg("netlink_send_ext: bad netlink ack type", "type=%d", hdr->nlmsg_type);
debug("netlink_send_ext: short netlink ack: %d\n", hdr->nlmsg_type);
return -1;
}
@@ -1011,7 +1011,7 @@ static void initialize_wifi_devices(void)
mac_addr[5] = device_id;
int ret = hwsim80211_create_device(&nlmsg, sock, hwsim_family_id, mac_addr);
if (ret < 0)
- fail("initialize_wifi_devices: failed to create device #%d", device_id);
+ failmsg("initialize_wifi_devices: failed to create device", "device=%d", device_id);
// For each device, unless HWSIM_ATTR_NO_VIF is passed, a network interface is created
// automatically. Such interfaces are named "wlan0", "wlan1" and so on.
@@ -1019,7 +1019,7 @@ static void initialize_wifi_devices(void)
interface[4] += device_id;
if (nl80211_setup_ibss_interface(&nlmsg, sock, nl80211_family_id, interface, &ibss_props) < 0)
- fail("initialize_wifi_devices: failed set up IBSS network for #%d", device_id);
+ failmsg("initialize_wifi_devices: failed set up IBSS network", "device=%d", device_id);
}
// Wait for all devices to join the IBSS network
@@ -1028,7 +1028,8 @@ static void initialize_wifi_devices(void)
interface[4] += device_id;
int ret = await_ifla_operstate(&nlmsg, interface, IF_OPER_UP);
if (ret < 0)
- fail("initialize_wifi_devices: get_ifla_operstate failed for #%d, ret %d", device_id, ret);
+ failmsg("initialize_wifi_devices: get_ifla_operstate failed",
+ "device=%d, ret=%d", device_id, ret);
}
close(sock);
@@ -1561,7 +1562,7 @@ static int read_tun(char* data, int size)
// Tun sometimes returns EBADFD, unclear if it's a kernel bug or not.
if (errno == EAGAIN || errno == EBADFD)
return -1;
- fail("tun: read failed with %d", rv);
+ fail("tun read failed");
}
return rv;
}
@@ -1856,8 +1857,6 @@ static long syz_io_uring_submit(volatile long a0, volatile long a1, volatile lon
static long syz_usbip_server_init(volatile long a0)
{
- int socket_pair[2];
- char buffer[100];
// port_alloc[0] corresponds to ports which can be used by usb2 and
// port_alloc[1] corresponds to ports which can be used by usb3.
static int port_alloc[2];
@@ -1865,9 +1864,9 @@ static long syz_usbip_server_init(volatile long a0)
int speed = (int)a0;
bool usb3 = (speed == USB_SPEED_SUPER);
- int rc = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair);
- if (rc < 0)
- fail("syz_usbip_server_init : socketpair failed: %d", rc);
+ int socket_pair[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair))
+ fail("syz_usbip_server_init: socketpair failed");
int client_fd = socket_pair[0];
int server_fd = socket_pair[1];
@@ -1887,6 +1886,7 @@ static long syz_usbip_server_init(volatile long a0)
// Under normal USB/IP usage, devid represents the device ID on the server.
// When fuzzing with syzkaller we don't have an actual server or an actual device, so use 0 for devid.
+ char buffer[100];
sprintf(buffer, "%d %d %s %d", port_num, client_fd, "0", speed);
write_file("/sys/devices/platform/vhci_hcd.0/attach", buffer);
@@ -2495,7 +2495,7 @@ static bool process_command_pkt(int fd, char* buf, ssize_t buf_size)
struct hci_command_hdr* hdr = (struct hci_command_hdr*)buf;
if (buf_size < (ssize_t)sizeof(struct hci_command_hdr) ||
hdr->plen != buf_size - sizeof(struct hci_command_hdr)) {
- fail("invalid size: %zx", buf_size);
+ failmsg("process_command_pkt: invalid size", "suze=%zx", buf_size);
}
switch (hdr->opcode) {
@@ -3078,7 +3078,7 @@ static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables, i
case ENOPROTOOPT:
return;
}
- fail("iptable checkpoint %d: socket failed", family);
+ failmsg("iptable checkpoint: socket(SOCK_STREAM, IPPROTO_TCP) failed", "family=%d", family);
}
for (int i = 0; i < num_tables; i++) {
struct ipt_table_desc* table = &tables[i];
@@ -3092,25 +3092,26 @@ static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables, i
case ENOPROTOOPT:
continue;
}
- fail("iptable checkpoint %s/%d: getsockopt(IPT_SO_GET_INFO)", table->name, family);
+ failmsg("iptable checkpoint: getsockopt(IPT_SO_GET_INFO) failed",
+ "table=%s, family=%d", table->name, family);
}
debug("iptable checkpoint %s/%d: checkpoint entries=%d hooks=%x size=%d\n",
table->name, family, table->info.num_entries,
table->info.valid_hooks, table->info.size);
if (table->info.size > sizeof(table->replace.entrytable))
- fail("iptable checkpoint %s/%d: table size is too large: %u",
- table->name, family, table->info.size);
+ failmsg("iptable checkpoint: table size is too large", "table=%s, family=%d, size=%u",
+ table->name, family, table->info.size);
if (table->info.num_entries > XT_MAX_ENTRIES)
- fail("iptable checkpoint %s/%d: too many counters: %u",
- table->name, family, table->info.num_entries);
+ failmsg("iptable checkpoint: too many counters", "table=%s, family=%d, counters=%d",
+ table->name, family, table->info.num_entries);
struct ipt_get_entries entries;
memset(&entries, 0, sizeof(entries));
strcpy(entries.name, table->name);
entries.size = table->info.size;
optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
- fail("iptable checkpoint %s/%d: getsockopt(IPT_SO_GET_ENTRIES)",
- table->name, family);
+ failmsg("iptable checkpoint: getsockopt(IPT_SO_GET_ENTRIES) failed",
+ "table=%s, family=%d", table->name, family);
table->replace.valid_hooks = table->info.valid_hooks;
table->replace.num_entries = table->info.num_entries;
table->replace.size = table->info.size;
@@ -3130,7 +3131,7 @@ static void reset_iptables(struct ipt_table_desc* tables, int num_tables, int fa
case ENOPROTOOPT:
return;
}
- fail("iptable %d: socket failed", family);
+ failmsg("iptable: socket(SOCK_STREAM, IPPROTO_TCP) failed", "family=%d", family);
}
for (int i = 0; i < num_tables; i++) {
struct ipt_table_desc* table = &tables[i];
@@ -3141,7 +3142,8 @@ static void reset_iptables(struct ipt_table_desc* tables, int num_tables, int fa
strcpy(info.name, table->name);
socklen_t optlen = sizeof(info);
if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
- fail("iptable %s/%d: getsockopt(IPT_SO_GET_INFO)", table->name, family);
+ failmsg("iptable: getsockopt(IPT_SO_GET_INFO) failed",
+ "table=%s, family=%d", table->name, family);
if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
struct ipt_get_entries entries;
memset(&entries, 0, sizeof(entries));
@@ -3149,7 +3151,8 @@ static void reset_iptables(struct ipt_table_desc* tables, int num_tables, int fa
entries.size = table->info.size;
optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
- fail("iptable %s/%d: getsockopt(IPT_SO_GET_ENTRIES)", table->name, family);
+ failmsg("iptable: getsockopt(IPT_SO_GET_ENTRIES) failed",
+ "table=%s, family=%d", table->name, family);
if (memcmp(table->replace.entrytable, entries.entrytable, table->info.size) == 0)
continue;
}
@@ -3159,7 +3162,8 @@ static void reset_iptables(struct ipt_table_desc* tables, int num_tables, int fa
table->replace.counters = counters;
optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size;
if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
- fail("iptable %s/%d: setsockopt(IPT_SO_SET_REPLACE)", table->name, family);
+ failmsg("iptable: setsockopt(IPT_SO_SET_REPLACE) failed",
+ "table=%s, family=%d", table->name, family);
}
close(fd);
}
@@ -3173,7 +3177,7 @@ static void checkpoint_arptables(void)
case ENOPROTOOPT:
return;
}
- fail("arptable checkpoint: socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
+ fail("arptable checkpoint: socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) failed");
}
for (unsigned i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
struct arpt_table_desc* table = &arpt_tables[i];
@@ -3187,23 +3191,23 @@ static void checkpoint_arptables(void)
case ENOPROTOOPT:
continue;
}
- fail("arptable checkpoint %s: getsockopt(ARPT_SO_GET_INFO)", table->name);
+ failmsg("arptable checkpoint: getsockopt(ARPT_SO_GET_INFO) failed", "table=%s", table->name);
}
debug("arptable checkpoint %s: entries=%d hooks=%x size=%d\n",
table->name, table->info.num_entries, table->info.valid_hooks, table->info.size);
if (table->info.size > sizeof(table->replace.entrytable))
- fail("arptable checkpoint %s: table size is too large: %u",
- table->name, table->info.size);
+ failmsg("arptable checkpoint: table size is too large",
+ "table=%s, size=%u", table->name, table->info.size);
if (table->info.num_entries > XT_MAX_ENTRIES)
- fail("arptable checkpoint %s: too many counters: %u",
- table->name, table->info.num_entries);
+ failmsg("arptable checkpoint: too many counters",
+ "table=%s, counters=%u", table->name, table->info.num_entries);
struct arpt_get_entries entries;
memset(&entries, 0, sizeof(entries));
strcpy(entries.name, table->name);
entries.size = table->info.size;
optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
- fail("arptable checkpoint %s: getsockopt(ARPT_SO_GET_ENTRIES)", table->name);
+ failmsg("arptable checkpoint: getsockopt(ARPT_SO_GET_ENTRIES) failed", "table=%s", table->name);
table->replace.valid_hooks = table->info.valid_hooks;
table->replace.num_entries = table->info.num_entries;
table->replace.size = table->info.size;
@@ -3234,7 +3238,7 @@ static void reset_arptables()
strcpy(info.name, table->name);
socklen_t optlen = sizeof(info);
if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
- fail("arptable %s:getsockopt(ARPT_SO_GET_INFO)", table->name);
+ failmsg("arptable: getsockopt(ARPT_SO_GET_INFO) failed", "table=%s", table->name);
if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
struct arpt_get_entries entries;
memset(&entries, 0, sizeof(entries));
@@ -3242,7 +3246,7 @@ static void reset_arptables()
entries.size = table->info.size;
optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
- fail("arptable %s: getsockopt(ARPT_SO_GET_ENTRIES)", table->name);
+ failmsg("arptable: getsockopt(ARPT_SO_GET_ENTRIES) failed", "table=%s", table->name);
if (memcmp(table->replace.entrytable, entries.entrytable, table->info.size) == 0)
continue;
debug("arptable %s: data changed\n", table->name);
@@ -3255,7 +3259,8 @@ static void reset_arptables()
table->replace.counters = counters;
optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size;
if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
- fail("arptable %s: setsockopt(ARPT_SO_SET_REPLACE)", table->name);
+ failmsg("arptable: setsockopt(ARPT_SO_SET_REPLACE) failed",
+ "table=%s", table->name);
}
close(fd);
}
@@ -3328,19 +3333,21 @@ static void checkpoint_ebtables(void)
case ENOPROTOOPT:
continue;
}
- fail("ebtable checkpoint %s: getsockopt(EBT_SO_GET_INIT_INFO)", table->name);
+ failmsg("ebtable checkpoint: getsockopt(EBT_SO_GET_INIT_INFO) failed",
+ "table=%s", table->name);
}
debug("ebtable checkpoint %s: entries=%d hooks=%x size=%d\n",
table->name, table->replace.nentries, table->replace.valid_hooks,
table->replace.entries_size);
if (table->replace.entries_size > sizeof(table->entrytable))
- fail("ebtable checkpoint %s: table size is too large: %u",
- table->name, table->replace.entries_size);
+ failmsg("ebtable checkpoint: table size is too large", "table=%s, size=%u",
+ table->name, table->replace.entries_size);
table->replace.num_counters = 0;
table->replace.entries = table->entrytable;
optlen = sizeof(table->replace) + table->replace.entries_size;
if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace, &optlen))
- fail("ebtable checkpoint %s: getsockopt(EBT_SO_GET_INIT_ENTRIES)", table->name);
+ failmsg("ebtable checkpoint: getsockopt(EBT_SO_GET_INIT_ENTRIES) failed",
+ "table=%s", table->name);
}
close(fd);
}
@@ -3365,7 +3372,7 @@ static void reset_ebtables()
strcpy(replace.name, table->name);
socklen_t optlen = sizeof(replace);
if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
- fail("ebtable %s: getsockopt(EBT_SO_GET_INFO)", table->name);
+ failmsg("ebtable: getsockopt(EBT_SO_GET_INFO)", "table=%s", table->name);
replace.num_counters = 0;
table->replace.entries = 0;
for (unsigned h = 0; h < NF_BR_NUMHOOKS; h++)
@@ -3376,7 +3383,7 @@ static void reset_ebtables()
replace.entries = entrytable;
optlen = sizeof(replace) + replace.entries_size;
if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
- fail("ebtable %s: getsockopt(EBT_SO_GET_ENTRIES)", table->name);
+ failmsg("ebtable: getsockopt(EBT_SO_GET_ENTRIES) failed", "table=%s", table->name);
if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
continue;
}
@@ -3391,7 +3398,7 @@ static void reset_ebtables()
table->replace.entries = table->entrytable;
optlen = sizeof(table->replace) + table->replace.entries_size;
if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
- fail("ebtable %s: setsockopt(EBT_SO_SET_ENTRIES)", table->name);
+ failmsg("ebtable: setsockopt(EBT_SO_SET_ENTRIES) failed", "table=%s", table->name);
}
close(fd);
}
@@ -3978,19 +3985,18 @@ const size_t UNTRUSTED_APP_NUM_GROUPS = sizeof(UNTRUSTED_APP_GROUPS) / sizeof(UN
// - No library dependency
// - No dynamic memory allocation
// - Uses fail() instead of returning an error code
-static void syz_getcon(char* context, size_t context_size)
+static void getcon(char* context, size_t context_size)
{
int fd = open(SELINUX_CONTEXT_FILE, O_RDONLY);
-
if (fd < 0)
- fail("getcon: Couldn't open %s", SELINUX_CONTEXT_FILE);
+ fail("getcon: couldn't open context file");
ssize_t nread = read(fd, context, context_size);
close(fd);
if (nread <= 0)
- fail("getcon: Failed to read from %s", SELINUX_CONTEXT_FILE);
+ fail("getcon: failed to read context file");
// The contents of the context file MAY end with a newline
// and MAY not have a null terminator. Handle this here.
@@ -4002,7 +4008,7 @@ static void syz_getcon(char* context, size_t context_size)
// - No library dependency
// - No dynamic memory allocation
// - Uses fail() instead of returning an error code
-static void syz_setcon(const char* context)
+static void setcon(const char* context)
{
char new_context[512];
@@ -4010,7 +4016,7 @@ static void syz_setcon(const char* context)
int fd = open(SELINUX_CONTEXT_FILE, O_WRONLY);
if (fd < 0)
- fail("setcon: Could not open %s", SELINUX_CONTEXT_FILE);
+ fail("setcon: could not open context file");
ssize_t bytes_written = write(fd, context, strlen(context));
@@ -4019,45 +4025,29 @@ static void syz_setcon(const char* context)
close(fd);
if (bytes_written != (ssize_t)strlen(context))
- fail("setcon: Could not write entire context. Wrote %zi, expected %zu", bytes_written, strlen(context));
+ failmsg("setcon: could not write entire context", "wrote=%zi, expected=%zu", bytes_written, strlen(context));
// Validate the transition by checking the context
- syz_getcon(new_context, sizeof(new_context));
+ getcon(new_context, sizeof(new_context));
if (strcmp(context, new_context) != 0)
- fail("setcon: Failed to change to %s, context is %s", context, new_context);
-}
-
-// Similar to libselinux getfilecon(3), but:
-// - No library dependency
-// - No dynamic memory allocation
-// - Uses fail() instead of returning an error code
-static int syz_getfilecon(const char* path, char* context, size_t context_size)
-{
- int length = getxattr(path, SELINUX_XATTR_NAME, context, context_size);
-
- if (length == -1)
- fail("getfilecon: getxattr failed");
-
- return length;
+ failmsg("setcon: failed to change", "want=%s, context=%s", context, new_context);
}
// Similar to libselinux setfilecon(3), but:
// - No library dependency
// - No dynamic memory allocation
// - Uses fail() instead of returning an error code
-static void syz_setfilecon(const char* path, const char* context)
+static void setfilecon(const char* path, const char* context)
{
char new_context[512];
if (setxattr(path, SELINUX_XATTR_NAME, context, strlen(context) + 1, 0) != 0)
fail("setfilecon: setxattr failed");
-
- if (syz_getfilecon(path, new_context, sizeof(new_context)) <= 0)
- fail("setfilecon: getfilecon failed");
-
+ if (getxattr(path, SELINUX_XATTR_NAME, new_context, sizeof(new_context)) < 0)
+ fail("setfilecon: getxattr failed");
if (strcmp(context, new_context) != 0)
- fail("setfilecon: could not set context to %s, currently %s", context, new_context);
+ failmsg("setfilecon: could not set context", "want=%s, got=%s", context, new_context);
}
#define SYZ_HAVE_SANDBOX_ANDROID 1
@@ -4088,13 +4078,13 @@ static int do_sandbox_android(void)
#endif
if (chown(".", UNTRUSTED_APP_UID, UNTRUSTED_APP_UID) != 0)
- fail("chmod failed");
+ fail("do_sandbox_android: chmod failed");
if (setgroups(UNTRUSTED_APP_NUM_GROUPS, UNTRUSTED_APP_GROUPS) != 0)
- fail("setgroups failed");
+ fail("do_sandbox_android: setgroups failed");
if (setresgid(UNTRUSTED_APP_GID, UNTRUSTED_APP_GID, UNTRUSTED_APP_GID) != 0)
- fail("setresgid failed");
+ fail("do_sandbox_android: setresgid failed");
#if GOARCH_arm || GOARCH_arm64 || GOARCH_386 || GOARCH_amd64
// Will fail() if anything fails.
@@ -4104,13 +4094,13 @@ static int do_sandbox_android(void)
#endif
if (setresuid(UNTRUSTED_APP_UID, UNTRUSTED_APP_UID, UNTRUSTED_APP_UID) != 0)
- fail("setresuid failed");
+ fail("do_sandbox_android: setresuid failed");
// setresuid and setresgid clear the parent-death signal.
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
- syz_setfilecon(".", SELINUX_LABEL_APP_DATA_FILE);
- syz_setcon(SELINUX_CONTEXT_UNTRUSTED_APP);
+ setfilecon(".", SELINUX_LABEL_APP_DATA_FILE);
+ setcon(SELINUX_CONTEXT_UNTRUSTED_APP);
loop();
doexit(1);
@@ -4454,7 +4444,7 @@ static void setup_fault()
if (!write_file(files[i].file, files[i].val)) {
debug("failed to write %s: %d\n", files[i].file, errno);
if (files[i].fatal)
- fail("failed to write %s", files[i].file);
+ failmsg("failed to write fault injection file", "file=%s", files[i].file);
}
}
}
@@ -4473,12 +4463,12 @@ static void setup_leak()
{
// Flush boot leaks.
if (!write_file(KMEMLEAK_FILE, "scan"))
- fail("failed to write %s", KMEMLEAK_FILE);
+ fail("failed to write(kmemleak, \"scan\")");
sleep(5); // account for MSECS_MIN_AGE
if (!write_file(KMEMLEAK_FILE, "scan"))
- fail("failed to write %s", KMEMLEAK_FILE);
+ fail("failed to write(kmemleak, \"scan\")");
if (!write_file(KMEMLEAK_FILE, "clear"))
- fail("failed to write %s", KMEMLEAK_FILE);
+ fail("failed to write(kmemleak, \"clear\")");
}
#define SYZ_HAVE_LEAK_CHECK 1
@@ -4490,7 +4480,7 @@ static void check_leaks(void)
{
int fd = open(KMEMLEAK_FILE, O_RDWR);
if (fd == -1)
- fail("failed to open(\"%s\")", KMEMLEAK_FILE);
+ fail("failed to open(kmemleak)");
// KMEMLEAK has false positives. To mitigate most of them, it checksums
// potentially leaked objects, and reports them only on the next scan
// iff the checksum does not change. Because of that we do the following
@@ -4501,28 +4491,28 @@ static void check_leaks(void)
// hopefully these are true positives during the previous testing cycle.
uint64 start = current_time_ms();
if (write(fd, "scan", 4) != 4)
- fail("failed to write(%s, \"scan\")", KMEMLEAK_FILE);
+ fail("failed to write(kmemleak, \"scan\")");
sleep(1);
// Account for MSECS_MIN_AGE
// (1 second less because scanning will take at least a second).
while (current_time_ms() - start < 4 * 1000)
sleep(1);
if (write(fd, "scan", 4) != 4)
- fail("failed to write(%s, \"scan\")", KMEMLEAK_FILE);
+ fail("failed to write(kmemleak, \"scan\")");
static char buf[128 << 10];
ssize_t n = read(fd, buf, sizeof(buf) - 1);
if (n < 0)
- fail("failed to read(%s)", KMEMLEAK_FILE);
+ fail("failed to read(kmemleak)");
int nleaks = 0;
if (n != 0) {
sleep(1);
if (write(fd, "scan", 4) != 4)
- fail("failed to write(%s, \"scan\")", KMEMLEAK_FILE);
+ fail("failed to write(kmemleak, \"scan\")");
if (lseek(fd, 0, SEEK_SET) < 0)
- fail("failed to lseek(%s)", KMEMLEAK_FILE);
+ fail("failed to lseek(kmemleak)");
n = read(fd, buf, sizeof(buf) - 1);
if (n < 0)
- fail("failed to read(%s)", KMEMLEAK_FILE);
+ fail("failed to read(kmemleak)");
buf[n] = 0;
char* pos = buf;
char* end = buf + n;
@@ -4552,7 +4542,7 @@ static void check_leaks(void)
}
}
if (write(fd, "clear", 5) != 5)
- fail("failed to write(%s, \"clear\")", KMEMLEAK_FILE);
+ fail("failed to write(kmemleak, \"clear\")");
close(fd);
if (nleaks)
doexit(1);
@@ -4589,7 +4579,7 @@ static void setup_kcsan_filterlist(char** frames, int nframes, bool suppress)
{
int fd = open(KCSAN_DEBUGFS_FILE, O_WRONLY);
if (fd == -1)
- fail("failed to open(\"%s\")", KCSAN_DEBUGFS_FILE);
+ fail("failed to open kcsan debugfs file");
printf("%s KCSAN reports in functions: ",
suppress ? "suppressing" : "only showing");
diff --git a/executor/common_usb_netbsd.h b/executor/common_usb_netbsd.h
index 56c9718be..138b50557 100644
--- a/executor/common_usb_netbsd.h
+++ b/executor/common_usb_netbsd.h
@@ -218,14 +218,11 @@ static volatile long syz_usb_connect_impl(int fd, uint64 speed, uint64 dev_len,
analyze_usb_device(index);
#endif
- int rv = vhci_setport(fd, 1);
- if (rv != 0) {
- fail("syz_usb_connect: vhci_setport failed with %d", errno);
- }
+ if (vhci_setport(fd, 1))
+ fail("syz_usb_connect: vhci_setport failed with");
- rv = vhci_usb_attach(fd);
- if (rv != 0) {
- debug("syz_usb_connect: vhci_usb_attach failed with %d\n", rv);
+ if (vhci_usb_attach(fd)) {
+ debug("syz_usb_connect: vhci_usb_attach failed with %d\n", errno);
return -1;
}
debug("syz_usb_connect: vhci_usb_attach success\n");
@@ -234,8 +231,7 @@ static volatile long syz_usb_connect_impl(int fd, uint64 speed, uint64 dev_len,
while (!done) {
vhci_request_t req;
- rv = vhci_usb_recv(fd, &req, sizeof(req));
- if (rv != 0) {
+ if (vhci_usb_recv(fd, &req, sizeof(req))) {
debug("syz_usb_connect: vhci_usb_recv failed with %d\n", errno);
return -1;
}
@@ -285,6 +281,7 @@ static volatile long syz_usb_connect_impl(int fd, uint64 speed, uint64 dev_len,
else
memset(data, 0, response_length);
+ int rv = 0;
if (req.u.ctrl.bmRequestType & UE_DIR_IN) {
debug("syz_usb_connect: writing %d bytes\n", response_length);
if (response_length > 0) {
@@ -329,9 +326,8 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1,
debug_dump_data(dev, dev_len);
int fd = vhci_open();
- if (fd < 0) {
- fail("syz_usb_connect: vhci_open failed with %d", errno);
- }
+ if (fd < 0)
+ fail("syz_usb_connect: vhci_open failed");
long res = syz_usb_connect_impl(fd, speed, dev_len, dev, descs, &lookup_connect_response_out_generic);
close(fd);
return res;
diff --git a/executor/cov_filter.h b/executor/cov_filter.h
index 26eb67ec8..a8b6624fe 100644
--- a/executor/cov_filter.h
+++ b/executor/cov_filter.h
@@ -30,7 +30,7 @@ static void init_coverage_filter()
void* preferred = (void*)0x110f230000ull;
cov_filter = (cov_filter_t*)mmap(preferred, st.st_size, PROT_READ, MAP_PRIVATE, f, 0);
if (cov_filter != preferred)
- fail("failed to initialize coverage filter bitmap at %p", preferred);
+ failmsg("failed to mmap coverage filter bitmap", "want=%p, got=%p", preferred, cov_filter);
if ((uint32)st.st_size != sizeof(uint32) * 2 + ((cov_filter->pcsize >> 4) + 7) / 8)
fail("bad coverage filter bitmap size");
close(f);
diff --git a/executor/executor.cc b/executor/executor.cc
index 5bb2d7226..80fdc49cc 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -75,7 +75,12 @@ const int kCoverSize = 256 << 10;
const int kFailStatus = 67;
// Logical error (e.g. invalid input program), use as an assert() alternative.
-static NORETURN PRINTF(1, 2) void fail(const char* msg, ...);
+// If such error happens 10+ times in a row, it will be detected as a bug by syz-fuzzer.
+// syz-fuzzer will fail and syz-manager will create a bug for this.
+// Note: err is used for bug deduplication, thus distinction between err (constant message)
+// and msg (varying part).
+static NORETURN void fail(const char* err);
+static NORETURN PRINTF(2, 3) void failmsg(const char* err, const char* msg, ...);
// Just exit (e.g. due to temporal ENOMEM error).
static NORETURN PRINTF(1, 2) void exitf(const char* msg, ...);
static NORETURN void doexit(int status);
@@ -524,9 +529,9 @@ void receive_handshake()
handshake_req req = {};
int n = read(kInPipeFd, &req, sizeof(req));
if (n != sizeof(req))
- fail("handshake read failed: %d", n);
+ failmsg("handshake read failed", "read=%d", n);
if (req.magic != kInMagic)
- fail("bad handshake magic 0x%llx", req.magic);
+ failmsg("bad handshake magic", "magic=0x%llx", req.magic);
parse_env_flags(req.flags);
procid = req.pid;
}
@@ -548,9 +553,9 @@ void receive_execute()
if (read(kInPipeFd, &req, sizeof(req)) != (ssize_t)sizeof(req))
fail("control pipe read failed");
if (req.magic != kInMagic)
- fail("bad execute request magic 0x%llx", req.magic);
+ failmsg("bad execute request magic", "magic=0x%llx", req.magic);
if (req.prog_size > kMaxInput)
- fail("bad execute prog size 0x%llx", req.prog_size);
+ failmsg("bad execute prog size", "size=0x%llx", req.prog_size);
parse_env_flags(req.env_flags);
procid = req.pid;
syscall_timeout_ms = req.syscall_timeout_ms;
@@ -574,7 +579,8 @@ void receive_execute()
flag_fault_call, flag_fault_nth, syscall_timeout_ms, program_timeout_ms, slowdown_scale,
req.prog_size, flag_coverage_filter);
if (syscall_timeout_ms == 0 || program_timeout_ms <= syscall_timeout_ms || slowdown_scale == 0)
- fail("bad timeouts: %llu/%llu/%llu", syscall_timeout_ms, program_timeout_ms, slowdown_scale);
+ failmsg("bad timeouts", "syscall=%llu, program=%llu, scale=%llu",
+ syscall_timeout_ms, program_timeout_ms, slowdown_scale);
if (SYZ_EXECUTOR_USES_SHMEM) {
if (req.prog_size)
fail("need_prog: no program");
@@ -592,7 +598,7 @@ void receive_execute()
break;
}
if (pos != req.prog_size)
- fail("bad input size %lld, want %lld", pos, req.prog_size);
+ failmsg("bad input size", "size=%lld, want=%lld", pos, req.prog_size);
}
#if GOOS_akaros
@@ -681,7 +687,7 @@ retry:
switch (csum_kind) {
case arg_csum_inet: {
if (size != 2)
- fail("inet checksum must be 2 bytes, not %llu", size);
+ failmsg("bag inet checksum size", "size=%llu", size);
debug_verbose("calculating checksum for %p\n", csum_addr);
struct csum_inet csum;
csum_inet_init(&csum);
@@ -698,16 +704,15 @@ retry:
NONFAILING(csum_inet_update(&csum, (const uint8*)chunk_value, chunk_size));
break;
case arg_csum_chunk_const:
- if (chunk_size != 2 && chunk_size != 4 && chunk_size != 8) {
- fail("bad checksum const chunk size %lld", chunk_size);
- }
+ if (chunk_size != 2 && chunk_size != 4 && chunk_size != 8)
+ failmsg("bad checksum const chunk size", "size=%lld", chunk_size);
// Here we assume that const values come to us big endian.
debug_verbose("#%lld: const chunk, value: %llx, size: %llu\n",
chunk, chunk_value, chunk_size);
csum_inet_update(&csum, (const uint8*)&chunk_value, chunk_size);
break;
default:
- fail("bad checksum chunk kind %llu", chunk_kind);
+ failmsg("bad checksum chunk kind", "kind=%llu", chunk_kind);
}
}
uint16 csum_value = csum_inet_digest(&csum);
@@ -716,12 +721,12 @@ retry:
break;
}
default:
- fail("bad checksum kind %llu", csum_kind);
+ failmsg("bad checksum kind", "kind=%llu", csum_kind);
}
break;
}
default:
- fail("bad argument type %llu", typ);
+ failmsg("bad argument type", "type=%llu", typ);
}
continue;
}
@@ -735,10 +740,10 @@ retry:
// Normal syscall.
if (call_num >= ARRAY_SIZE(syscalls))
- fail("invalid command number %llu", call_num);
+ failmsg("invalid syscall number", "call_num=%llu", call_num);
const call_t* call = &syscalls[call_num];
if (call->attrs.disabled)
- fail("executing disabled syscall %s", call->name);
+ failmsg("executing disabled syscall", "syscall=%s", call->name);
if (prog_extra_timeout < call->attrs.prog_timeout)
prog_extra_timeout = call->attrs.prog_timeout * slowdown_scale;
if (strncmp(syscalls[call_num].name, "syz_usb", strlen("syz_usb")) == 0)
@@ -748,7 +753,7 @@ retry:
uint64 copyout_index = read_input(&input_pos);
uint64 num_args = read_input(&input_pos);
if (num_args > kMaxArgs)
- fail("command has bad number of arguments %llu", num_args);
+ failmsg("command has bad number of arguments", "args=%llu", num_args);
uint64 args[kMaxArgs] = {};
for (uint64 i = 0; i < num_args; i++)
args[i] = read_arg(&input_pos);
@@ -856,8 +861,8 @@ thread_t* schedule_call(int call_index, int call_num, bool colliding, uint64 cop
exitf("out of threads");
thread_t* th = &threads[i];
if (event_isset(&th->ready) || !event_isset(&th->done) || th->executing)
- fail("bad thread state in schedule: ready=%d done=%d executing=%d",
- event_isset(&th->ready), event_isset(&th->done), th->executing);
+ failmsg("bad thread state in schedule", "ready=%d done=%d executing=%d",
+ event_isset(&th->ready), event_isset(&th->done), th->executing);
last_scheduled = th;
th->colliding = colliding;
th->copyout_pos = pos;
@@ -925,8 +930,8 @@ void write_coverage_signal(cover_t* cov, uint32* signal_count_pos, uint32* cover
void handle_completion(thread_t* th)
{
if (event_isset(&th->ready) || !event_isset(&th->done) || !th->executing)
- fail("bad thread state in completion: ready=%d done=%d executing=%d",
- event_isset(&th->ready), event_isset(&th->done), th->executing);
+ failmsg("bad thread state in completion", "ready=%d done=%d executing=%d",
+ event_isset(&th->ready), event_isset(&th->done), th->executing);
if (th->res != (intptr_t)-1)
copyout_call_results(th);
if (!collide && !th->colliding) {
@@ -947,7 +952,7 @@ void handle_completion(thread_t* th)
event_isset(&th1->ready), event_isset(&th1->done),
th1->call_index, (uint64)th1->res, th1->reserrno);
}
- fail("running = %d", running);
+ fail("negative running");
}
}
@@ -955,7 +960,7 @@ void copyout_call_results(thread_t* th)
{
if (th->copyout_index != no_copyout) {
if (th->copyout_index >= kMaxCommands)
- fail("result idx %lld overflows kMaxCommands", th->copyout_index);
+ failmsg("result overflows kMaxCommands", "index=%lld", th->copyout_index);
results[th->copyout_index].executed = true;
results[th->copyout_index].val = th->res;
}
@@ -965,7 +970,7 @@ void copyout_call_results(thread_t* th)
case instr_copyout: {
uint64 index = read_input(&th->copyout_pos);
if (index >= kMaxCommands)
- fail("result idx %lld overflows kMaxCommands", index);
+ failmsg("result overflows kMaxCommands", "index=%lld", index);
char* addr = (char*)read_input(&th->copyout_pos);
uint64 size = read_input(&th->copyout_pos);
uint64 val = 0;
@@ -1008,7 +1013,7 @@ void write_call_output(thread_t* th, bool finished)
kcov_comparison_t* start = (kcov_comparison_t*)(th->cov.data + sizeof(uint64));
kcov_comparison_t* end = start + ncomps;
if ((char*)end > th->cov.data_end)
- fail("too many comparisons %u", ncomps);
+ failmsg("too many comparisons", "ncomps=%u", ncomps);
cover_unprotect(&th->cov);
std::sort(start, end);
ncomps = std::unique(start, end) - start;
@@ -1143,7 +1148,7 @@ void execute_call(thread_t* th)
if (flag_coverage) {
cover_collect(&th->cov);
if (th->cov.size >= kCoverSize)
- fail("#%d: too much cover %u", th->id, th->cov.size);
+ failmsg("too much cover", "thr=%d, cov=%u", th->id, th->cov.size);
}
th->fault_injected = false;
@@ -1217,7 +1222,7 @@ void copyin(char* addr, uint64 val, uint64 size, uint64 bf, uint64 bf_off, uint6
debug_verbose("copyin: addr=%p val=0x%llx size=%llu bf=%llu bf_off=%llu bf_len=%llu\n",
addr, val, size, bf, bf_off, bf_len);
if (bf != binary_format_native && bf != binary_format_bigendian && (bf_off != 0 || bf_len != 0))
- fail("bitmask for string format %llu/%llu", bf_off, bf_len);
+ failmsg("bitmask for string format", "off=%llu, len=%llu", bf_off, bf_len);
switch (bf) {
case binary_format_native:
case binary_format_bigendian:
@@ -1235,26 +1240,26 @@ void copyin(char* addr, uint64 val, uint64 size, uint64 bf, uint64 bf_off, uint6
copyin_int<uint64>(addr, val, bf, bf_off, bf_len);
break;
default:
- fail("copyin: bad argument size %llu", size);
+ failmsg("copyin: bad argument size", "size=%llu", size);
});
break;
case binary_format_strdec:
if (size != 20)
- fail("bad strdec size %llu", size);
+ failmsg("bad strdec size", "size=%llu", size);
NONFAILING(sprintf((char*)addr, "%020llu", val));
break;
case binary_format_strhex:
if (size != 18)
- fail("bad strhex size %llu", size);
+ failmsg("bad strhex size", "size=%llu", size);
NONFAILING(sprintf((char*)addr, "0x%016llx", val));
break;
case binary_format_stroct:
if (size != 23)
- fail("bad stroct size %llu", size);
+ failmsg("bad stroct size", "size=%llu", size);
NONFAILING(sprintf((char*)addr, "%023llo", val));
break;
default:
- fail("unknown binary format %llu", bf);
+ failmsg("unknown binary format", "format=%llu", bf);
}
}
@@ -1275,7 +1280,7 @@ bool copyout(char* addr, uint64 size, uint64* res)
*res = *(uint64*)addr;
break;
default:
- fail("copyout: bad argument size %llu", size);
+ failmsg("copyout: bad argument size", "size=%llu", size);
});
}
@@ -1287,20 +1292,20 @@ uint64 read_arg(uint64** input_posp)
uint64 size, bf, bf_off, bf_len;
uint64 val = read_const_arg(input_posp, &size, &bf, &bf_off, &bf_len);
if (bf != binary_format_native && bf != binary_format_bigendian)
- fail("bad argument binary format %llu", bf);
+ failmsg("bad argument binary format", "format=%llu", bf);
if (bf_off != 0 || bf_len != 0)
- fail("bad argument bitfield %llu/%llu", bf_off, bf_len);
+ failmsg("bad argument bitfield", "off=%llu, len=%llu", bf_off, bf_len);
return swap(val, size, bf);
}
case arg_result: {
uint64 meta = read_input(input_posp);
uint64 bf = meta >> 8;
if (bf != binary_format_native)
- fail("bad result argument format %llu", bf);
+ failmsg("bad result argument format", "format=%llu", bf);
return read_result(input_posp);
}
default:
- fail("bad argument type %llu", typ);
+ failmsg("bad argument type", "type=%llu", typ);
}
}
@@ -1309,7 +1314,7 @@ uint64 swap(uint64 v, uint64 size, uint64 bf)
if (bf == binary_format_native)
return v;
if (bf != binary_format_bigendian)
- fail("bad binary format in swap: %llu", bf);
+ failmsg("bad binary format in swap", "format=%llu", bf);
switch (size) {
case 2:
return htobe16(v);
@@ -1318,7 +1323,7 @@ uint64 swap(uint64 v, uint64 size, uint64 bf)
case 8:
return htobe64(v);
default:
- fail("bad big-endian int size %llu", size);
+ failmsg("bad big-endian int size", "size=%llu", size);
}
}
@@ -1343,7 +1348,7 @@ uint64 read_result(uint64** input_posp)
uint64 op_add = read_input(input_posp);
uint64 arg = read_input(input_posp);
if (idx >= kMaxCommands)
- fail("command refers to bad result %lld", idx);
+ failmsg("command refers to bad result", "result=%lld", idx);
if (results[idx].executed) {
arg = results[idx].val;
if (op_div != 0)
@@ -1357,7 +1362,7 @@ uint64 read_input(uint64** input_posp, bool peek)
{
uint64* input_pos = *input_posp;
if ((char*)input_pos >= input_data + kMaxInput)
- fail("input command overflows input %p: [%p:%p)", input_pos, input_data, input_data + kMaxInput);
+ failmsg("input command overflows input", "pos=%p: [%p:%p)", input_pos, input_data, input_data + kMaxInput);
if (!peek)
*input_posp = input_pos + 1;
return *input_pos;
@@ -1367,8 +1372,8 @@ uint64 read_input(uint64** input_posp, bool peek)
uint32* write_output(uint32 v)
{
if (output_pos < output_data || (char*)output_pos >= (char*)output_data + kMaxOutput)
- fail("output overflow: pos=%p region=[%p:%p]",
- output_pos, output_data, (char*)output_data + kMaxOutput);
+ failmsg("output overflow", "pos=%p region=[%p:%p]",
+ output_pos, output_data, (char*)output_data + kMaxOutput);
*output_pos = v;
return output_pos++;
}
@@ -1376,8 +1381,8 @@ uint32* write_output(uint32 v)
uint32* write_output_64(uint64 v)
{
if (output_pos < output_data || (char*)(output_pos + 1) >= (char*)output_data + kMaxOutput)
- fail("output overflow: pos=%p region=[%p:%p]",
- output_pos, output_data, (char*)output_data + kMaxOutput);
+ failmsg("output overflow", "pos=%p region=[%p:%p]",
+ output_pos, output_data, (char*)output_data + kMaxOutput);
*(uint64*)output_pos = v;
output_pos += 2;
return output_pos;
@@ -1393,7 +1398,7 @@ void write_completed(uint32 completed)
void kcov_comparison_t::write()
{
if (type > (KCOV_CMP_CONST | KCOV_CMP_SIZE_MASK))
- fail("invalid kcov comp type %llx", type);
+ failmsg("invalid kcov comp type", "type=%llx", type);
// Write order: type arg1 arg2 pc.
write_output((uint32)type);
@@ -1499,18 +1504,21 @@ void setup_features(char** enable, int n)
}
#endif
if (!found)
- fail("unknown feature %s", enable[i]);
+ failmsg("setup features: unknown feature", "feature=%s", enable[i]);
}
}
-void fail(const char* msg, ...)
+void failmsg(const char* err, const char* msg, ...)
{
int e = errno;
- va_list args;
- va_start(args, msg);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, " (errno %d)\n", e);
+ if (msg) {
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ }
+ fprintf(stderr, " (errno %d: %s)\n", e, strerror(e));
+ fprintf(stderr, "SYZFAIL: %s\n", err);
// fail()'s are often used during the validation of kernel reactions to queries
// that were issued by pseudo syscalls implementations. As fault injection may
@@ -1528,6 +1536,11 @@ void fail(const char* msg, ...)
doexit(kFailStatus);
}
+void fail(const char* err)
+{
+ failmsg(err, 0);
+}
+
void exitf(const char* msg, ...)
{
int e = errno;
diff --git a/executor/executor_bsd.h b/executor/executor_bsd.h
index fa31099fe..8ef8186f8 100644
--- a/executor/executor_bsd.h
+++ b/executor/executor_bsd.h
@@ -61,7 +61,7 @@ static void cover_open(cover_t* cov, bool extra)
if (fd == -1)
fail("open of /dev/kcov failed");
if (dup2(fd, cov->fd) < 0)
- fail("failed to dup2(%d, %d) cover fd", fd, cov->fd);
+ failmsg("failed to dup cover fd", "from=%d, to=%d", fd, cov->fd);
close(fd);
#if GOOS_freebsd
diff --git a/executor/executor_fuchsia.h b/executor/executor_fuchsia.h
index 88a1ccff5..646711079 100644
--- a/executor/executor_fuchsia.h
+++ b/executor/executor_fuchsia.h
@@ -15,7 +15,7 @@ static void os_init(int argc, char** argv, void* data, size_t data_size)
{
zx_status_t status = syz_mmap((size_t)data, data_size);
if (status != ZX_OK)
- fail("mmap of data segment failed: %s (%d)", zx_status_get_string(status), status);
+ failmsg("mmap of data segment failed", "status=%s (%d)", zx_status_get_string(status), status);
}
static intptr_t execute_syscall(const call_t* c, intptr_t a[kMaxArgs])
diff --git a/executor/executor_linux.h b/executor/executor_linux.h
index 57c2638ea..3a0620fcd 100644
--- a/executor/executor_linux.h
+++ b/executor/executor_linux.h
@@ -79,7 +79,7 @@ static void cover_open(cover_t* cov, bool extra)
if (fd == -1)
fail("open of /sys/kernel/debug/kcov failed");
if (dup2(fd, cov->fd) < 0)
- fail("filed to dup2(%d, %d) cover fd", fd, cov->fd);
+ failmsg("filed to dup cover fd", "from=%d, to=%d", fd, cov->fd);
close(fd);
const int kcov_init_trace = is_kernel_64_bit ? KCOV_INIT_TRACE64 : KCOV_INIT_TRACE32;
const int cover_size = extra ? kExtraCoverSize : kCoverSize;
diff --git a/executor/style_test.go b/executor/style_test.go
index 3b0ee8ce7..9c83f2536 100644
--- a/executor/style_test.go
+++ b/executor/style_test.go
@@ -111,12 +111,20 @@ if (foo)
},
},
{
- pattern: `\s*(fail|exitf)\(".*\\n`,
+ pattern: `(fail|exitf)\(".*\\n`,
message: "Don't use \\n in fail/exitf messages",
tests: []string{
`fail("some message with new line\n");`,
},
},
+ {
+ pattern: `fail(msg)?\("[^"]*%`,
+ message: "DON'T",
+ tests: []string{
+ `fail("format %s string")`,
+ `failmsg("format %s string", "format")`,
+ },
+ },
}
for _, check := range checks {
re := regexp.MustCompile(check.pattern)