void do_syscall(struct syscallrecord *rec) { struct syscallentry *entry; struct msg_syscallprep scmsg; struct childdata *child = this_child(); unsigned int call; init_msgchildhdr(&scmsg.hdr, SYSCALL_PREP, pids[child->num], child->num); scmsg.sequence_nr = child->op_nr; scmsg.nr = rec->nr; scmsg.is32bit = rec->do32bit; scmsg.a1 = rec->a1; scmsg.a2 = rec->a2; scmsg.a3 = rec->a3; scmsg.a4 = rec->a4; scmsg.a5 = rec->a5; scmsg.a6 = rec->a6; rec->tp = scmsg.hdr.tp; sendudp((char *) &scmsg, sizeof(scmsg)); call = rec->nr; entry = syscalls[call].entry; if (entry->flags & EXTRA_FORK) do_extrafork(rec); else /* common-case, do the syscall in this child process. */ __do_syscall(rec, BEFORE); /* timestamp again for when we returned */ clock_gettime(CLOCK_MONOTONIC, &rec->tp); }
/* * Return a pointer a previous mmap() that we did, either during startup, * or from a fuzz result. */ struct map * get_map(void) { struct object *obj = NULL; struct childdata *child = this_child(); bool global; enum objecttype type = 0; /* * Some of the fd providers need weird mappings on startup. * (fd-perf for eg), these are called from the main process, * and hence don't have a valid this_child, so we address the * initial mappings list directly. */ if (child == NULL) global = OBJ_GLOBAL; else global = OBJ_LOCAL; while (obj == NULL) { switch (rnd() % 3) { case 0: type = OBJ_MMAP_ANON; break; case 1: type = OBJ_MMAP_FILE; break; case 2: type = OBJ_MMAP_TESTFILE; break; } obj = get_random_object(type, global); } return &obj->map; }
static void sigxcpu_handler(__unused__ int sig) { struct childdata *child = this_child(); child->xcpu_count++; siglongjmp(ret_jump, 1); }
FILE *find_logfile_handle(void) { struct childdata *child; pid_t pid; pid = getpid(); if (pid == mainpid) return mainlogfile; child = this_child(); if (child != NULL) return child->logfile; return NULL; }
/* used in several sanitise_* functions. */ struct map * common_set_mmap_ptr_len(void) { struct syscallrecord *rec; struct map *map; struct childdata *child = this_child(); rec = &child->syscall; map = (struct map *) rec->a1; if (map == NULL) { rec->a1 = 0; rec->a2 = 0; return NULL; } rec->a1 = (unsigned long) map->ptr; rec->a2 = rnd() % map->size; rec->a2 &= PAGE_MASK; return map; }
/* * Flush any pending log writes to disk. * Only to be called from child context. */ void synclogs(void) { struct childdata *child; int fd; child = this_child(); if (child->logdirty == FALSE) return; fflush(child->logfile); fd = fileno(child->logfile); if (fd != -1) (void) fsync(fd); child->logdirty = FALSE; /* If we're flushing the child log, may as well flush * any other logs while we're writing to disk. */ (void)fflush(mainlogfile); fsync(fileno(mainlogfile)); }
/* * Return a pointer a previous mmap() that we did, either during startup, * or from a fuzz result. */ struct map * get_map(void) { struct object *obj; struct map *map; struct childdata *child = this_child(); bool global; /* * Some of the fd providers need weird mappings on startup. * (fd-perf for eg), these are called from the main process, * and hence don't have a valid this_child, so we address the * initial mappings list directly. */ if (child == NULL) global = OBJ_GLOBAL; else global = OBJ_LOCAL; obj = get_random_object(OBJ_MMAP, global); map = &obj->map; return map; }
/* * Set up a childs local mapping list. * A child inherits the initial mappings, and will add to them * when it successfully completes mmap() calls. */ void init_child_mappings(void) { struct list_head *globallist, *node; struct objhead *head; struct childdata *child = this_child(); init_object_lists(OBJ_LOCAL); head = &child->objects[OBJ_MMAP]; head->destroy = &map_destructor; globallist = shm->global_objects[OBJ_MMAP].list; /* Copy the initial mapping list to the child. * Note we're only copying pointers here, the actual mmaps * will be faulted into the child when they get accessed. */ list_for_each(node, globallist) { struct map *m; struct object *globalobj, *newobj; globalobj = (struct object *) node; m = &globalobj->map; newobj = zmalloc(sizeof(struct object)); newobj->map.ptr = m->ptr; newobj->map.name = strdup(m->name); newobj->map.size = m->size; newobj->map.prot = m->prot; /* We leave type as 'INITIAL' until we change the mapping * by mprotect/mremap/munmap etc.. */ newobj->map.type = TRINITY_MAP_INITIAL; add_object(newobj, OBJ_LOCAL, OBJ_MMAP); } }
void handle_syscall_ret(struct syscallrecord *rec) { struct syscallentry *entry; struct msg_syscallresult scmsg; struct childdata *child = this_child(); unsigned int call; init_msgchildhdr(&scmsg.hdr, SYSCALL_RESULT, pids[child->num], child->num); scmsg.hdr.tp = rec->tp; scmsg.sequence_nr = child->op_nr; scmsg.retval = rec->retval; scmsg.errno_post = rec->errno_post; sendudp((char *) &scmsg, sizeof(scmsg)); call = rec->nr; entry = syscalls[call].entry; if (rec->retval == -1UL) { int err = rec->errno_post; /* only check syscalls that completed. */ //FIXME: how else would we get here? if (rec->state == AFTER) { if (err == ENOSYS) deactivate_enosys(rec, entry, call); entry->failures++; if (err < NR_ERRNOS) { entry->errnos[err]++; } else { // "These should never be seen by user programs." // But trinity isn't a 'normal' user program, we're doing // stuff that libc hides from apps. if (err < 512 || err > 530) printf("errno out of range after doing %s: %d:%s\n", entry->name, err, strerror(err)); } shm->stats.failures++; } } else { handle_success(rec); // Believe me folks, you'll never get bored with winning entry->successes++; shm->stats.successes++; } entry->attempted++; generic_post(entry->arg1type, rec->a1); generic_post(entry->arg2type, rec->a2); generic_post(entry->arg3type, rec->a3); generic_post(entry->arg4type, rec->a4); generic_post(entry->arg5type, rec->a5); generic_post(entry->arg6type, rec->a6); if (entry->post) entry->post(rec); check_uid(); generic_free_arg(rec); }