github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/executor/common_fuchsia.h (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  // This file is shared between executor and csource package.
     5  
     6  #include <fcntl.h>
     7  #include <lib/fdio/directory.h>
     8  #include <poll.h>
     9  #include <signal.h>
    10  #include <stdlib.h>
    11  #include <sys/file.h>
    12  #include <sys/ioctl.h>
    13  #include <sys/socket.h>
    14  #include <sys/stat.h>
    15  #include <sys/time.h>
    16  #include <sys/types.h>
    17  #include <sys/uio.h>
    18  #include <time.h>
    19  #include <unistd.h>
    20  #include <utime.h>
    21  #include <zircon/process.h>
    22  #include <zircon/status.h>
    23  #include <zircon/syscalls.h>
    24  
    25  #if SYZ_EXECUTOR || __NR_get_root_resource
    26  #include <lib/ddk/driver.h>
    27  #endif
    28  
    29  #if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
    30  #include <pthread.h>
    31  #include <setjmp.h>
    32  #include <zircon/syscalls/debug.h>
    33  #include <zircon/syscalls/exception.h>
    34  #include <zircon/syscalls/object.h>
    35  
    36  static __thread int skip_segv;
    37  static __thread jmp_buf segv_env;
    38  
    39  static void segv_handler(void)
    40  {
    41  	if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED)) {
    42  		debug("recover: skipping\n");
    43  		longjmp(segv_env, 1);
    44  	}
    45  	debug("recover: exiting\n");
    46  	doexit(SIGSEGV);
    47  }
    48  
    49  static zx_status_t update_exception_thread_regs(zx_handle_t exception)
    50  {
    51  	zx_handle_t thread;
    52  	zx_status_t status = zx_exception_get_thread(exception, &thread);
    53  	if (status != ZX_OK) {
    54  		debug("zx_exception_get_thread failed: %s (%d)\n", zx_status_get_string(status), status);
    55  		return status;
    56  	}
    57  
    58  	zx_thread_state_general_regs_t regs;
    59  	status = zx_thread_read_state(thread, ZX_THREAD_STATE_GENERAL_REGS,
    60  				      &regs, sizeof(regs));
    61  	if (status != ZX_OK) {
    62  		debug("zx_thread_read_state failed: %d %s (%d)\n",
    63  		      (int)sizeof(regs), zx_status_get_string(status), status);
    64  	} else {
    65  #if GOARCH_amd64
    66  		regs.rip = (uint64)(void*)&segv_handler;
    67  #elif GOARCH_arm64
    68  		regs.pc = (uint64)(void*)&segv_handler;
    69  #else
    70  #error "unsupported arch"
    71  #endif
    72  		status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, &regs, sizeof(regs));
    73  		if (status != ZX_OK) {
    74  			debug("zx_thread_write_state failed: %s (%d)\n", zx_status_get_string(status), status);
    75  		}
    76  	}
    77  
    78  	zx_handle_close(thread);
    79  	return status;
    80  }
    81  
    82  static void* ex_handler(void* arg)
    83  {
    84  	zx_handle_t exception_channel = (zx_handle_t)(long)arg;
    85  	for (int i = 0; i < 10000; i++) {
    86  		zx_status_t status = zx_object_wait_one(exception_channel, ZX_CHANNEL_READABLE, ZX_TIME_INFINITE, NULL);
    87  		if (status != ZX_OK) {
    88  			debug("zx_object_wait_one failed: %s (%d)\n", zx_status_get_string(status), status);
    89  			continue;
    90  		}
    91  
    92  		zx_exception_info_t info;
    93  		zx_handle_t exception;
    94  		status = zx_channel_read(exception_channel, 0, &info, &exception, sizeof(info), 1, NULL, NULL);
    95  		if (status != ZX_OK) {
    96  			debug("zx_channel_read failed: %s (%d)\n", zx_status_get_string(status), status);
    97  			continue;
    98  		}
    99  
   100  		debug("got exception: type=%d tid=%llu\n", info.type, (unsigned long long)(info.tid));
   101  		status = update_exception_thread_regs(exception);
   102  		if (status != ZX_OK) {
   103  			debug("failed to update exception thread registers: %s (%d)\n", zx_status_get_string(status), status);
   104  		}
   105  
   106  		uint32 state = ZX_EXCEPTION_STATE_HANDLED;
   107  		status = zx_object_set_property(exception, ZX_PROP_EXCEPTION_STATE, &state, sizeof(state));
   108  		if (status != ZX_OK) {
   109  			debug("zx_object_set_property(ZX_PROP_EXCEPTION_STATE) failed: %s (%d)\n", zx_status_get_string(status), status);
   110  		}
   111  		zx_handle_close(exception);
   112  	}
   113  	doexit(1);
   114  	return 0;
   115  }
   116  
   117  static void install_segv_handler(void)
   118  {
   119  	zx_status_t status;
   120  	zx_handle_t exception_channel;
   121  	if ((status = zx_task_create_exception_channel(zx_process_self(), 0, &exception_channel)) != ZX_OK)
   122  		failmsg("zx_task_create_exception_channel failed",
   123  			"status=%s (%d)", zx_status_get_string(status), status);
   124  	pthread_t th;
   125  	if (pthread_create(&th, 0, ex_handler, (void*)(long)exception_channel))
   126  		fail("pthread_create failed");
   127  }
   128  
   129  #define NONFAILING(...)                                              \
   130  	({                                                           \
   131  		int ok = 1;                                          \
   132  		__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
   133  		if (sigsetjmp(segv_env, 0) == 0) {                   \
   134  			__VA_ARGS__;                                 \
   135  		} else                                               \
   136  			ok = 0;                                      \
   137  		__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
   138  		ok;                                                  \
   139  	})
   140  #endif
   141  
   142  #if SYZ_EXECUTOR || SYZ_THREADED
   143  #include <unistd.h>
   144  
   145  // Fuchsia's pthread_cond_timedwait just returns immidiately, so we use simple spin wait.
   146  typedef struct {
   147  	int state;
   148  } event_t;
   149  
   150  static void event_init(event_t* ev)
   151  {
   152  	ev->state = 0;
   153  }
   154  
   155  static void event_reset(event_t* ev)
   156  {
   157  	ev->state = 0;
   158  }
   159  
   160  static void event_set(event_t* ev)
   161  {
   162  	if (ev->state)
   163  		exitf("event already set");
   164  	__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
   165  }
   166  
   167  static void event_wait(event_t* ev)
   168  {
   169  	while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
   170  		usleep(200);
   171  }
   172  
   173  static int event_isset(event_t* ev)
   174  {
   175  	return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
   176  }
   177  
   178  static int event_timedwait(event_t* ev, uint64 timeout_ms)
   179  {
   180  	uint64 start = current_time_ms();
   181  	for (;;) {
   182  		if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
   183  			return 1;
   184  		if (current_time_ms() - start > timeout_ms)
   185  			return 0;
   186  		usleep(200);
   187  	}
   188  }
   189  #endif
   190  
   191  #if SYZ_EXECUTOR || __NR_syz_mmap
   192  long syz_mmap(size_t addr, size_t size)
   193  {
   194  	zx_handle_t root = zx_vmar_root_self();
   195  	zx_info_vmar_t info;
   196  	zx_status_t status = zx_object_get_info(root, ZX_INFO_VMAR, &info, sizeof(info), 0, 0);
   197  	if (status != ZX_OK) {
   198  		debug("zx_object_get_info(ZX_INFO_VMAR) failed: %s (%d)", zx_status_get_string(status), status);
   199  		return status;
   200  	}
   201  	zx_handle_t vmo;
   202  	status = zx_vmo_create(size, 0, &vmo);
   203  	if (status != ZX_OK) {
   204  		debug("zx_vmo_create failed: %s (%d)\n", zx_status_get_string(status), status);
   205  		return status;
   206  	}
   207  
   208  	uintptr_t mapped_addr;
   209  	status = zx_vmar_map(root, ZX_VM_FLAG_SPECIFIC_OVERWRITE | ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE,
   210  			     addr - info.base, vmo, 0, size,
   211  			     &mapped_addr);
   212  
   213  	zx_status_t close_vmo_status = zx_handle_close(vmo);
   214  	if (close_vmo_status != ZX_OK) {
   215  		debug("zx_handle_close(vmo) failed with: %s (%d)\n", zx_status_get_string(close_vmo_status), close_vmo_status);
   216  	}
   217  	return status;
   218  }
   219  #endif
   220  
   221  #if SYZ_EXECUTOR || __NR_syz_process_self
   222  static long syz_process_self(void)
   223  {
   224  	return zx_process_self();
   225  }
   226  #endif
   227  
   228  #if SYZ_EXECUTOR || __NR_syz_thread_self
   229  static long syz_thread_self(void)
   230  {
   231  	return zx_thread_self();
   232  }
   233  #endif
   234  
   235  #if SYZ_EXECUTOR || __NR_syz_vmar_root_self
   236  static long syz_vmar_root_self(void)
   237  {
   238  	return zx_vmar_root_self();
   239  }
   240  #endif
   241  
   242  #if SYZ_EXECUTOR || __NR_syz_job_default
   243  static long syz_job_default(void)
   244  {
   245  	return zx_job_default();
   246  }
   247  #endif
   248  
   249  #if SYZ_EXECUTOR || __NR_syz_future_time
   250  static long syz_future_time(volatile long when)
   251  {
   252  	zx_time_t delta_ms = 10000;
   253  	switch (when) {
   254  	case 0:
   255  		delta_ms = 5;
   256  		break;
   257  	case 1:
   258  		delta_ms = 30;
   259  		break;
   260  	}
   261  	zx_time_t now = 0;
   262  	zx_clock_read(ZX_CLOCK_MONOTONIC, &now);
   263  	return now + delta_ms * 1000 * 1000;
   264  }
   265  #endif
   266  
   267  #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
   268  static void loop();
   269  static int do_sandbox_none(void)
   270  {
   271  	loop();
   272  	return 0;
   273  }
   274  #endif
   275  
   276  // Ugly way to work around gcc's "error: function called through a non-compatible type".
   277  // The macro is used in generated C code.
   278  #define CAST(f) ({void* p = (void*)f; p; })