static int mm_check_read_msghdr(const struct msghdr *msg) { if (!mm_check_read(msg, sizeof(struct msghdr))) return 0; if (msg->msg_namelen && !mm_check_read(msg->msg_name, msg->msg_namelen)) return 0; if (msg->msg_iovlen && !mm_check_read(msg->msg_iov, sizeof(struct iovec) * msg->msg_iovlen)) return 0; if (msg->msg_controllen && !mm_check_read(msg->msg_control, msg->msg_controllen)) return 0; for (int i = 0; i < msg->msg_iovlen; i++) { log_info("iov %d: [%p, %p)", i, msg->msg_iov[i].iov_base, (uintptr_t)msg->msg_iov[i].iov_base + msg->msg_iov[i].iov_len); if (!mm_check_read(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len)) return 0; } return 1; }
DEFINE_SYSCALL(nanosleep, const struct timespec *, req, struct timespec *, rem) { log_info("nanosleep(0x%p, 0x%p)", req, rem); if (!mm_check_read(req, sizeof(struct timespec)) || rem && !mm_check_write(rem, sizeof(struct timespec))) return -L_EFAULT; LARGE_INTEGER delay_interval; delay_interval.QuadPart = 0ULL - (((uint64_t)req->tv_sec * 1000000000ULL + req->tv_nsec) / 100ULL); NtDelayExecution(FALSE, &delay_interval); return 0; }
DEFINE_SYSCALL(sendto, int, sockfd, const void *, buf, size_t, len, int, flags, const struct sockaddr *, dest_addr, int, addrlen) { log_info("sendto(%d, %p, %d, %x, %p, %d)", sockfd, buf, len, flags, dest_addr, addrlen); if (!mm_check_read(buf, len)) return -L_EFAULT; if (dest_addr && !mm_check_read(dest_addr, addrlen)) return -L_EFAULT; struct file *f = vfs_get(sockfd); if (!f) return -L_EBADF; int r; if (!f->op_vtable->sendto) { log_error("sendto() not implemented."); r = -L_ENOTSOCK; } else r = f->op_vtable->sendto(f, buf, len, flags, dest_addr, addrlen); vfs_release(f); return r; }
DEFINE_SYSCALL(setrlimit, int, resource, const struct rlimit *, rlim) { log_info("setrlimit(%d, %p)\n", resource, rlim); if (!mm_check_read(rlim, sizeof(struct rlimit))) return -EFAULT; switch (resource) { default: log_error("Unsupported resource: %d\n", resource); return -EINVAL; } }
DEFINE_SYSCALL(setsockopt, int, sockfd, int, level, int, optname, const void *, optval, int, optlen) { log_info("setsockopt(%d, %d, %d, %p, %d)", sockfd, level, optname, optval, optlen); if (optval && !mm_check_read(optval, optlen)) return -L_EFAULT; struct file *f = vfs_get(sockfd); if (!f) return -L_EBADF; int r; if (!f->op_vtable->setsockopt) { log_error("setsockopt() not implemented."); r = -L_ENOTSOCK; } else r = f->op_vtable->setsockopt(f, level, optname, optval, optlen); vfs_release(f); return r; }
DEFINE_SYSCALL(send, int, sockfd, const void *, buf, size_t, len, int, flags) { log_info("send(%d, %p, %d, %x)", sockfd, buf, len, flags); if (!mm_check_read(buf, len)) return -L_EFAULT; struct file *f = vfs_get(sockfd); if (!f) return -L_EBADF; int r; if (!f->op_vtable->sendto) { log_error("send() not implemented."); r = -L_ENOTSOCK; } else r = f->op_vtable->sendto(f, buf, len, flags, NULL, 0); vfs_release(f); return r; }
DEFINE_SYSCALL(connect, int, sockfd, const struct sockaddr *, addr, size_t, addrlen) { log_info("connect(%d, %p, %d)", sockfd, addr, addrlen); if (!mm_check_read(addr, sizeof(struct sockaddr))) return -L_EFAULT; struct file *f = vfs_get(sockfd); if (!f) return -L_EBADF; int r; if (!f->op_vtable->connect) { log_error("connect() not implemented."); r = -L_ENOTSOCK; } else r = f->op_vtable->connect(f, addr, addrlen); vfs_release(f); return r; }
DEFINE_SYSCALL(socketcall, int, call, uintptr_t *, args) { if (call < 1 || call > SYS_SENDMMSG) return -L_EINVAL; if (!mm_check_read(args, nargs[call])) return -L_EFAULT; switch (call) { case SYS_SOCKET: return sys_socket(args[0], args[1], args[2]); case SYS_BIND: return sys_bind(args[0], (const struct sockaddr *)args[1], args[2]); case SYS_CONNECT: return sys_connect(args[0], (const struct sockaddr *)args[1], args[2]); case SYS_LISTEN: return sys_listen(args[0], args[1]); case SYS_ACCEPT: return sys_accept(args[0], (struct sockaddr *)args[1], (int *)args[2]); case SYS_GETSOCKNAME: return sys_getsockname(args[0], (struct sockaddr *)args[1], (int *)args[2]); case SYS_GETPEERNAME: return sys_getpeername(args[0], (struct sockaddr *)args[1], (int *)args[2]); case SYS_SEND: return sys_send(args[0], (const void *)args[1], args[2], args[3]); case SYS_RECV: return sys_recv(args[0], (void *)args[1], args[2], args[3]); case SYS_SENDTO: return sys_sendto(args[0], (const void *)args[1], args[2], args[3], (const struct sockaddr *)args[4], args[5]); case SYS_RECVFROM: return sys_recvfrom(args[0], (void *)args[1], args[2], args[3], (struct sockaddr *)args[4], (int *)args[5]); case SYS_SHUTDOWN: return sys_shutdown(args[0], args[1]); case SYS_SETSOCKOPT: return sys_setsockopt(args[0], args[1], args[2], (const void *)args[3], args[4]); case SYS_GETSOCKOPT: return sys_getsockopt(args[0], args[1], args[2], (void *)args[3], (int *)args[4]); case SYS_SENDMSG: return sys_sendmsg(args[0], (const struct msghdr *)args[1], args[2]); case SYS_RECVMSG: return sys_recvmsg(args[0], (struct msghdr *)args[1], args[2]); case SYS_ACCEPT4: return sys_accept4(args[0], (struct sockaddr *)args[1], (int *)args[2], args[3]); case SYS_SENDMMSG: return sys_sendmmsg(args[0], (struct mmsghdr *)args[1], args[2], args[3]); default: { log_error("Unimplemented socketcall: %d", call); return -L_EINVAL; } } }
static int dsp_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { AcquireSRWLockExclusive(&f->rw_lock); int r = 0; struct dsp_file *dsp = (struct dsp_file *)f; switch (cmd) { case SNDCTL_DSP_RESET: { log_info("SNDCTL_DSP_RESET."); dsp_reset(dsp); break; } case SNDCTL_DSP_SPEED: { if (!mm_check_read((int *)arg, sizeof(int))) { r = -L_EFAULT; break; } int speed = *(int *)arg; log_info("SNDCTL_DSP_SPEED: %d", speed); DWORD old_speed = dsp->format.nSamplesPerSec; dsp->format.nSamplesPerSec = speed; if (!dsp_test_format(&dsp->format)) { log_warning("Speed not supported."); dsp->format.nSamplesPerSec = old_speed; r = -L_EINVAL; } break; } case SNDCTL_DSP_STEREO: { if (!mm_check_read((int *)arg, sizeof(int))) { r = -L_EFAULT; break; } int c = *(int *)arg; log_info("SNDCTL_DSP_STEREO: %d", c); if (c == 0) dsp->format.nChannels = 1; else if (c == 1) dsp->format.nChannels = 2; else { log_warning("Invalid argument (can only be 0 or 1)."); r = -L_EINVAL; } break; } case SNDCTL_DSP_SETFMT: { if (!mm_check_read((int *)arg, sizeof(int))) { r = -L_EFAULT; break; } int fmt = *(int *)arg; log_info("SNDCTL_DSP_SETFMT: 0x%x", fmt); if (fmt == AFMT_S16_LE) dsp->format.wBitsPerSample = 16; else if (fmt == AFMT_U8) dsp->format.wBitsPerSample = 8; else { log_warning("Invalid argument (can only be AFMT_S16_LE or AFMT_U8)."); r = -L_EINVAL; } break; } case SNDCTL_DSP_GETFMTS: { if (!mm_check_write((int *)arg, sizeof(int))) { r = -L_EFAULT; break; } log_info("SNDCTL_DSP_GETFMTS"); *(int *)arg = AFMT_U8 | AFMT_S16_LE; break; } } ReleaseSRWLockExclusive(&f->rw_lock); return r; }