/* * This is the generic front-end to uuid_generate_random and * uuid_generate_time. It uses uuid_generate_random only if * /dev/urandom is available, since otherwise we won't have * high-quality randomness. */ void uuid_generate(uuid_t out) { if (get_random_fd() >= 0) uuid_generate_random(out); else uuid_generate_time(out); }
/* * Generate a series of random bytes. Use /dev/urandom if possible, * and if not, use srandom/random. */ static void get_random_bytes(void *buf, int nbytes) { int i, n = nbytes, fd = get_random_fd(); int lose_counter = 0; unsigned char *cp = (unsigned char *) buf; if (fd >= 0) { while (n > 0) { i = read(fd, cp, n); if (i <= 0) { if (lose_counter++ > 16) break; continue; } n -= i; cp += i; lose_counter = 0; } } /* * We do this all the time, but this is the only source of * randomness if /dev/random/urandom is out to lunch. */ for (cp = buf, i = 0; i < nbytes; i++) *cp++ ^= (rand() >> 7) & 0xFF; return; }
static void pppox_PX_PROTO_OL2TP_PPPoL2TPin6(struct sockaddr **addr, socklen_t *addrlen) { #ifdef USE_PPPOL2TPIN6 struct sockaddr_pppol2tpin6 *pppol2tpin6; pppol2tpin6 = zmalloc(sizeof(struct sockaddr_pppol2tpin6)); pppol2tpin6->sa_family = PF_PPPOX; pppol2tpin6->sa_protocol = rnd() % 3; pppol2tpin6->pppol2tp.pid = get_pid(); pppol2tpin6->pppol2tp.fd = get_random_fd(); pppol2tpin6->pppol2tp.s_tunnel = rnd(); pppol2tpin6->pppol2tp.s_session = rnd(); pppol2tpin6->pppol2tp.d_tunnel = rnd(); pppol2tpin6->pppol2tp.d_session = rnd(); pppol2tpin6->pppol2tp.addr.sin6_family = AF_INET6; pppol2tpin6->pppol2tp.addr.sin6_port = rnd(); pppol2tpin6->pppol2tp.addr.sin6_flowinfo = rnd(); pppol2tpin6->pppol2tp.addr.sin6_addr.s6_addr32[0] = 0; pppol2tpin6->pppol2tp.addr.sin6_addr.s6_addr32[1] = 0; pppol2tpin6->pppol2tp.addr.sin6_addr.s6_addr32[2] = 0; pppol2tpin6->pppol2tp.addr.sin6_addr.s6_addr32[3] = htonl(1); pppol2tpin6->pppol2tp.addr.sin6_scope_id = rnd(); *addr = (struct sockaddr *) pppol2tpin6; *addrlen = sizeof(struct sockaddr_pppol2tpin6); #endif }
/* * Generate a series of random bytes. Use /dev/urandom if possible, * and if not, use srandom/random. */ static void get_random_bytes(void *buf, int nbytes) { int i, fd = get_random_fd(); int lose_counter = 0; char *cp = (char *) buf; if (fd >= 0) { while (nbytes > 0) { i = read(fd, cp, nbytes); if ((i < 0) && ((errno == EINTR) || (errno == EAGAIN))) continue; if (i <= 0) { if (lose_counter++ == 8) break; continue; } nbytes -= i; cp += i; lose_counter = 0; } } /* XXX put something better here if no /dev/random! */ for (i = 0; i < nbytes; i++) *cp++ = rand() & 0xFF; return; }
static void sanitise_epoll_ctl(struct syscallrecord *rec) { struct epoll_event *ep; ep = zmalloc(sizeof(struct epoll_event)); ep->data.fd = get_random_fd(); ep->events = set_rand_bitmask(ARRAY_SIZE(epoll_flags), epoll_flags); rec->a4 = (unsigned long) ep; }
static void autofs_sanitise(const struct ioctl_group *grp, struct syscallrecord *rec) { struct autofs_dev_ioctl *arg; pick_random_ioctl(grp, rec); rec->a3 = (unsigned long) get_address(); switch (rec->a2) { case AUTOFS_DEV_IOCTL_VERSION: case AUTOFS_DEV_IOCTL_PROTOVER: case AUTOFS_DEV_IOCTL_PROTOSUBVER: case AUTOFS_DEV_IOCTL_OPENMOUNT: case AUTOFS_DEV_IOCTL_CLOSEMOUNT: case AUTOFS_DEV_IOCTL_READY: case AUTOFS_DEV_IOCTL_FAIL: case AUTOFS_DEV_IOCTL_SETPIPEFD: case AUTOFS_DEV_IOCTL_CATATONIC: case AUTOFS_DEV_IOCTL_TIMEOUT: case AUTOFS_DEV_IOCTL_REQUESTER: case AUTOFS_DEV_IOCTL_EXPIRE: case AUTOFS_DEV_IOCTL_ASKUMOUNT: case AUTOFS_DEV_IOCTL_ISMOUNTPOINT: arg = (struct autofs_dev_ioctl *) rec->a3; init_autofs_dev_ioctl(arg); arg->ioctlfd = get_random_fd(); arg->fail.token = rand(); arg->fail.status = rand(); if (RAND_BOOL()) { arg->size += 5; arg->path[0] = '/'; arg->path[1] = rand(); arg->path[2] = rand(); arg->path[3] = rand(); arg->path[4] = 0; } else { int i; arg->size += rand(); for (i=0; i < 10; ++i) arg->path[i] = rand(); } break; default: break; } }
static void autofs_sanitise(const struct ioctl_group *grp, int childno) { int i; struct autofs_dev_ioctl *arg; pick_random_ioctl(grp, childno); shm->a3[childno] = (unsigned long) page_rand; switch (shm->a2[childno]) { case AUTOFS_DEV_IOCTL_VERSION: case AUTOFS_DEV_IOCTL_PROTOVER: case AUTOFS_DEV_IOCTL_PROTOSUBVER: case AUTOFS_DEV_IOCTL_OPENMOUNT: case AUTOFS_DEV_IOCTL_CLOSEMOUNT: case AUTOFS_DEV_IOCTL_READY: case AUTOFS_DEV_IOCTL_FAIL: case AUTOFS_DEV_IOCTL_SETPIPEFD: case AUTOFS_DEV_IOCTL_CATATONIC: case AUTOFS_DEV_IOCTL_TIMEOUT: case AUTOFS_DEV_IOCTL_REQUESTER: case AUTOFS_DEV_IOCTL_EXPIRE: case AUTOFS_DEV_IOCTL_ASKUMOUNT: case AUTOFS_DEV_IOCTL_ISMOUNTPOINT: arg = (struct autofs_dev_ioctl *)shm->a3[childno]; init_autofs_dev_ioctl(arg); arg->ioctlfd = get_random_fd(); arg->fail.token = rand(); arg->fail.status = rand(); if (rand_bool()) { arg->size += 5; arg->path[0] = '/'; arg->path[1] = rand(); arg->path[2] = rand(); arg->path[3] = rand(); arg->path[4] = 0; } else { arg->size += rand(); for (i=0; i < 10; ++i) arg->path[i] = rand(); } break; default: break; } }
static void pppox_PX_PROTO_OL2TP_PPPoL2TP(struct sockaddr **addr, socklen_t *addrlen) { struct sockaddr_pppol2tp *pppol2tp; pppol2tp = zmalloc(sizeof(struct sockaddr_pppol2tp)); pppol2tp->sa_family = PF_PPPOX; pppol2tp->sa_protocol = rnd() % 3; pppol2tp->pppol2tp.pid = get_pid(); pppol2tp->pppol2tp.fd = get_random_fd(); pppol2tp->pppol2tp.addr.sin_addr.s_addr = random_ipv4_address(); pppol2tp->pppol2tp.s_tunnel = rnd(); pppol2tp->pppol2tp.s_session = rnd(); pppol2tp->pppol2tp.d_tunnel = rnd(); pppol2tp->pppol2tp.d_session = rnd(); *addr = (struct sockaddr *) pppol2tp; *addrlen = sizeof(struct sockaddr_pppol2tp); }
static void pppox_PX_PROTO_OL2TP_PPPoL2TPv3(struct sockaddr **addr, socklen_t *addrlen) { #ifdef USE_PPPOL2TPV3 struct sockaddr_pppol2tpv3 *pppol2tpv3; pppol2tpv3 = zmalloc(sizeof(struct sockaddr_pppol2tpv3)); pppol2tpv3->sa_family = PF_PPPOX; pppol2tpv3->sa_protocol = rnd() % 3; pppol2tpv3->pppol2tp.pid = get_pid(); pppol2tpv3->pppol2tp.fd = get_random_fd(); pppol2tpv3->pppol2tp.addr.sin_addr.s_addr = random_ipv4_address(); pppol2tpv3->pppol2tp.s_tunnel = rnd(); pppol2tpv3->pppol2tp.s_session = rnd(); pppol2tpv3->pppol2tp.d_tunnel = rnd(); pppol2tpv3->pppol2tp.d_session = rnd(); *addr = (struct sockaddr *) pppol2tpv3; *addrlen = sizeof(struct sockaddr_pppol2tpv3); #endif }
static void sanitise_poll(struct syscallrecord *rec) { struct pollfd *pollfd; unsigned int i; unsigned int num_fds = rand() % 10; unsigned long flags[] = { POLLIN, POLLPRI, POLLOUT, POLLRDHUP, POLLERR, POLLHUP, POLLNVAL, POLLRDNORM, POLLRDBAND, POLLWRNORM, POLLWRBAND, POLLMSG }; pollfd = zmalloc(num_fds * sizeof(struct pollfd)); for (i = 0; i < num_fds; i++) { pollfd[i].fd = get_random_fd(); pollfd[i].events = set_rand_bitmask(ARRAY_SIZE(flags), flags); } rec->a1 = (unsigned long) pollfd; rec->a2 = num_fds; }
static unsigned long fill_arg(struct syscallrecord *rec, unsigned int argnum) { struct syscallentry *entry; unsigned int call; enum argtype argtype; call = rec->nr; entry = syscalls[call].entry; if (argnum > entry->num_args) return 0; argtype = get_argtype(entry, argnum); switch (argtype) { case ARG_UNDEFINED: if (RAND_BOOL()) return (unsigned long) rand64(); return (unsigned long) get_writable_address(page_size); case ARG_FD: if (RAND_BOOL()) { unsigned int i; /* If this is the 2nd or more ARG_FD, make it unique */ for (i = 0; i < argnum; i++) { enum argtype arg; arg = get_argtype(entry, i); if (arg == ARG_FD) return get_new_random_fd(); } } return get_random_fd(); case ARG_LEN: return (unsigned long) get_len(); case ARG_ADDRESS: return handle_arg_address(rec, argnum); case ARG_NON_NULL_ADDRESS: return (unsigned long) get_non_null_address(); case ARG_MMAP: return (unsigned long) get_map(); case ARG_PID: return (unsigned long) get_pid(); case ARG_RANGE: return handle_arg_range(entry, argnum); case ARG_OP: /* Like ARG_LIST, but just a single value. */ return handle_arg_op(entry, argnum); case ARG_LIST: return handle_arg_list(entry, argnum); case ARG_CPU: return (unsigned long) get_cpu(); case ARG_PATHNAME: return (unsigned long) generate_pathname(); case ARG_IOVEC: return handle_arg_iovec(entry, rec, argnum); case ARG_IOVECLEN: case ARG_SOCKADDRLEN: /* We already set the len in the ARG_IOVEC/ARG_SOCKADDR case * So here we just return what we had set there. */ return get_argval(rec, argnum); case ARG_SOCKADDR: return handle_arg_sockaddr(entry, rec, argnum); case ARG_MODE_T: return handle_arg_mode_t(); case ARG_SOCKETINFO: return (unsigned long) get_rand_socketinfo(); } BUG("unreachable!\n"); }
static unsigned long fill_arg(struct syscallrecord *rec, unsigned int argnum) { struct syscallentry *entry; unsigned int call; enum argtype argtype; call = rec->nr; entry = syscalls[call].entry; if (argnum > entry->num_args) return 0; argtype = get_argtype(entry, argnum); switch (argtype) { case ARG_UNDEFINED: return (unsigned long) rand64(); case ARG_FD: return get_random_fd(); case ARG_LEN: return (unsigned long) get_len(); case ARG_ADDRESS: return handle_arg_address(rec, argnum); case ARG_NON_NULL_ADDRESS: return (unsigned long) get_non_null_address(); case ARG_MMAP: return (unsigned long) get_map(); case ARG_PID: return (unsigned long) get_pid(); case ARG_RANGE: return handle_arg_range(entry, argnum); case ARG_OP: /* Like ARG_LIST, but just a single value. */ return handle_arg_op(entry, argnum); case ARG_LIST: return handle_arg_list(entry, argnum); case ARG_RANDPAGE: return handle_arg_randpage(); case ARG_CPU: return (unsigned long) get_cpu(); case ARG_PATHNAME: return (unsigned long) generate_pathname(); case ARG_IOVEC: return handle_arg_iovec(entry, rec, argnum); case ARG_IOVECLEN: case ARG_SOCKADDRLEN: /* We already set the len in the ARG_IOVEC/ARG_SOCKADDR case * So here we just return what we had set there. */ return get_argval(rec, argnum); case ARG_SOCKADDR: return handle_arg_sockaddr(entry, rec, argnum); case ARG_MODE_T: return handle_arg_mode_t(); } BUG("unreachable!\n"); }
void sanitise_fcntl(int childno) { switch (shm->a2[childno]) { /* arg = fd */ case F_DUPFD: case F_DUPFD_CLOEXEC: case F_SETLEASE: shm->a3[childno] = (unsigned long) get_random_fd(); break; break; /* no arg */ case F_GETFD: case F_GETFL: case F_GETOWN: case F_GETSIG: case F_GETLEASE: case F_GETPIPE_SZ: break; case F_SETFD: /* arg = flags */ shm->a3[childno] = (unsigned int) rand32(); break; case F_SETFL: shm->a3[childno] = 0L; if (rand_bool()) shm->a3[childno] |= O_APPEND; if (rand_bool()) shm->a3[childno] |= O_ASYNC; if (rand_bool()) shm->a3[childno] |= O_DIRECT; if (rand_bool()) shm->a3[childno] |= O_NOATIME; if (rand_bool()) shm->a3[childno] |= O_NONBLOCK; break; /* arg = (struct flock *) */ case F_GETLK: case F_SETLK: case F_SETLKW: break; #ifdef HAVE_LK64 case F_GETLK64: break; case F_SETLK64: break; case F_SETLKW64: break; #endif case F_SETOWN: shm->a3[childno] = (unsigned long) get_pid(); break; /* arg = struct f_owner_ex *) */ case F_GETOWN_EX: case F_SETOWN_EX: break; case F_SETSIG: shm->a3[childno] = (unsigned long) rand32(); if (shm->a3[childno] == SIGINT) shm->a3[childno] = 0; /* restore default (SIGIO) */ break; case F_NOTIFY: shm->a3[childno] = 0L; if (rand_bool()) shm->a3[childno] |= DN_ACCESS; if (rand_bool()) shm->a3[childno] |= DN_MODIFY; if (rand_bool()) shm->a3[childno] |= DN_CREATE; if (rand_bool()) shm->a3[childno] |= DN_DELETE; if (rand_bool()) shm->a3[childno] |= DN_RENAME; if (rand_bool()) shm->a3[childno] |= DN_ATTRIB; break; case F_SETPIPE_SZ: shm->a3[childno] = rand32(); break; default: break; } }
static void sanitise_fcntl(struct syscallrecord *rec) { switch (rec->a2) { /* arg = fd */ case F_DUPFD: case F_DUPFD_CLOEXEC: case F_SETLEASE: rec->a3 = (unsigned long) get_random_fd(); break; /* no arg */ case F_GETFD: case F_GETFL: case F_GETOWN: case F_GETSIG: case F_GETLEASE: case F_GETPIPE_SZ: case F_GETOWNER_UIDS: break; case F_SETFD: /* arg = flags */ rec->a3 = (unsigned int) rand32(); break; case F_SETFL: rec->a3 = (unsigned long) random_fcntl_setfl_flags(); break; /* arg = (struct flock *) */ case F_GETLK: case F_SETLK: case F_SETLKW: break; #ifdef HAVE_LK64 case F_GETLK64: break; case F_SETLK64: break; case F_SETLKW64: break; #endif case F_SETOWN: rec->a3 = (unsigned long) get_pid(); break; /* arg = struct f_owner_ex *) */ case F_GETOWN_EX: case F_SETOWN_EX: break; case F_SETSIG: rec->a3 = (unsigned long) rand32(); if (rec->a3 == SIGINT) rec->a3 = 0; /* restore default (SIGIO) */ break; case F_NOTIFY: rec->a3 = 0L; if (rand_bool()) rec->a3 |= DN_ACCESS; if (rand_bool()) rec->a3 |= DN_MODIFY; if (rand_bool()) rec->a3 |= DN_CREATE; if (rand_bool()) rec->a3 |= DN_DELETE; if (rand_bool()) rec->a3 |= DN_RENAME; if (rand_bool()) rec->a3 |= DN_ATTRIB; break; case F_SETPIPE_SZ: rec->a3 = rand32(); break; default: break; } }
static void socket_destructor(struct object *obj) { struct socketinfo *si = &obj->sockinfo; struct linger ling = { .l_onoff = FALSE, .l_linger = 0 }; int fd; //FIXME: This is a workaround for a weird bug where we hang forevre // waiting for bluetooth sockets when we setsockopt. // Hopefully at some point we can remove this when someone figures out what's going on. if (si->triplet.family == PF_BLUETOOTH) return; /* Grab an fd, and nuke it before someone else uses it. */ fd = si->fd; si->fd = 0; /* disable linger */ (void) setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)); (void) shutdown(fd, SHUT_RDWR); if (close(fd) != 0) output(1, "failed to close socket [%d:%d:%d].(%s)\n", si->triplet.family, si->triplet.type, si->triplet.protocol, strerror(errno)); } static void socket_dump(struct object *obj, bool global) { struct socketinfo *si = &obj->sockinfo; struct msg_objcreatedsocket objmsg; output(2, "socket fd:%d domain:%u (%s) type:0x%u protocol:%u\n", si->fd, si->triplet.family, get_domain_name(si->triplet.family), si->triplet.type, si->triplet.protocol); init_msgobjhdr(&objmsg.hdr, OBJ_CREATED_SOCKET, global, obj); objmsg.si.fd = si->fd; objmsg.si.triplet.family = si->triplet.family; objmsg.si.triplet.type = si->triplet.type; objmsg.si.triplet.protocol = si->triplet.protocol; sendudp((char *) &objmsg, sizeof(objmsg)); } static int open_sockets(void) { struct objhead *head; int bytesread = -1; int ret; head = get_objhead(OBJ_GLOBAL, OBJ_FD_SOCKET); head->destroy = &socket_destructor; head->dump = &socket_dump; cachefile = open(cachefilename, O_RDONLY); if (cachefile < 0) { output(1, "Couldn't find socket cachefile. Regenerating.\n"); ret = generate_sockets(); output(1, "created %d sockets\n", nr_sockets); return ret; } lock_cachefile(F_RDLCK); while (bytesread != 0) { unsigned int domain, type, protocol; unsigned int buffer[3]; int fd; bytesread = read(cachefile, buffer, sizeof(int) * 3); if (bytesread == 0) { if (nr_sockets == 0) goto regenerate; break; } domain = buffer[0]; type = buffer[1]; protocol = buffer[2]; if (domain >= TRINITY_PF_MAX) { output(1, "cachefile contained invalid domain %u\n", domain); goto regenerate; } if ((do_specific_domain == TRUE && domain != specific_domain) || (no_domains[domain] == TRUE)) { output(1, "ignoring socket cachefile due to specific " "protocol request (or protocol disabled), " "and stale data in cachefile.\n"); regenerate: unlock_cachefile(); /* drop the reader lock. */ close(cachefile); unlink(cachefilename); ret = generate_sockets(); return ret; } fd = open_socket(domain, type, protocol); if (fd < 0) { output(1, "Cachefile is stale. Need to regenerate.\n"); goto regenerate; } /* check for ctrl-c */ if (shm->exit_reason != STILL_RUNNING) { close(cachefile); return FALSE; } } output(1, "%d sockets created based on info from socket cachefile.\n", nr_sockets); unlock_cachefile(); close(cachefile); return TRUE; } struct socketinfo * get_rand_socketinfo(void) { struct object *obj; /* When using victim files, sockets can be 0. */ if (objects_empty(OBJ_FD_SOCKET) == TRUE) return NULL; obj = get_random_object(OBJ_FD_SOCKET, OBJ_GLOBAL); return &obj->sockinfo; } static int get_rand_socket_fd(void) { struct socketinfo *sockinfo; sockinfo = get_rand_socketinfo(); if (sockinfo == NULL) return -1; return sockinfo->fd; } int fd_from_socketinfo(struct socketinfo *si) { if (si != NULL) { if (!(ONE_IN(1000))) return si->fd; } return get_random_fd(); } static const struct fd_provider socket_fd_provider = { .name = "sockets", .enabled = TRUE, .open = &open_sockets, .get = &get_rand_socket_fd, }; REG_FD_PROV(socket_fd_provider);