aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/common.h12
-rw-r--r--executor/executor.cc21
2 files changed, 25 insertions, 8 deletions
diff --git a/executor/common.h b/executor/common.h
index 004dcc341..40b2bf8d0 100644
--- a/executor/common.h
+++ b/executor/common.h
@@ -158,6 +158,18 @@ static void install_segv_handler()
__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
}
+#define BITMASK_LEN(type, bf_len) (type)((1ul << bf_len) - 1)
+
+#define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, bf_len) << bf_off)
+
+#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \
+ do { \
+ type new_val = *(type*)addr; \
+ new_val &= ~BITMASK_LEN_OFF(type, bf_off, bf_len); \
+ new_val |= ((type)val & BITMASK_LEN(type, bf_len)) << bf_off; \
+ *(type*)addr = new_val; \
+ } while (0)
+
#ifdef __NR_syz_emit_ethernet
static void vsnprintf_check(char* str, size_t size, const char* format, va_list args)
{
diff --git a/executor/executor.cc b/executor/executor.cc
index 94658a5cc..22eea9439 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -117,7 +117,7 @@ uint64_t read_input(uint64_t** input_posp, bool peek = false);
uint64_t read_arg(uint64_t** input_posp);
uint64_t read_result(uint64_t** input_posp);
void write_output(uint32_t v);
-void copyin(char* addr, uint64_t val, uint64_t size);
+void copyin(char* addr, uint64_t val, uint64_t size, uint64_t bf_off, uint64_t bf_len);
uint64_t copyout(char* addr, uint64_t size);
thread_t* schedule_call(int n, int call_index, int call_num, uint64_t num_args, uint64_t* args, uint64_t* pos);
void execute_call(thread_t* th);
@@ -299,12 +299,14 @@ retry:
switch (typ) {
case arg_const: {
uint64_t arg = read_input(&input_pos);
- copyin(addr, arg, size);
+ uint64_t bf_off = read_input(&input_pos);
+ uint64_t bf_len = read_input(&input_pos);
+ copyin(addr, arg, size, bf_off, bf_len);
break;
}
case arg_result: {
uint64_t val = read_result(&input_pos);
- copyin(addr, val, size);
+ copyin(addr, val, size, 0, 0);
break;
}
case arg_data: {
@@ -586,20 +588,20 @@ uint64_t cover_dedup(thread_t* th, uint64_t n)
return w;
}
-void copyin(char* addr, uint64_t val, uint64_t size)
+void copyin(char* addr, uint64_t val, uint64_t size, uint64_t bf_off, uint64_t bf_len)
{
NONFAILING(switch (size) {
case 1:
- *(uint8_t*)addr = val;
+ STORE_BY_BITMASK(uint8_t, addr, val, bf_off, bf_len);
break;
case 2:
- *(uint16_t*)addr = val;
+ STORE_BY_BITMASK(uint16_t, addr, val, bf_off, bf_len);
break;
case 4:
- *(uint32_t*)addr = val;
+ STORE_BY_BITMASK(uint32_t, addr, val, bf_off, bf_len);
break;
case 8:
- *(uint64_t*)addr = val;
+ STORE_BY_BITMASK(uint64_t, addr, val, bf_off, bf_len);
break;
default:
fail("copyin: bad argument size %lu", size);
@@ -637,6 +639,9 @@ uint64_t read_arg(uint64_t** input_posp)
switch (typ) {
case arg_const: {
arg = read_input(input_posp);
+ // Bitfields can't be args of a normal syscall, so just ignore them.
+ read_input(input_posp); // bit field offset
+ read_input(input_posp); // bit field length
break;
}
case arg_result: {