// SPDX-FileCopyrightText: edef // SPDX-License-Identifier: LicenseRef-NONE = TODO These have various sub-cases that vary significantly in complexity. == mmap == mprotect == munmap = Trivial == arch_prctl(ARCH_SET_FS, ptr) This is just `SETFS`. Safe to pass through, but also trivial to implement. == ioctl(fd, TCGETS, …) gcc likes doing these on various fds, but `return -ENOTTY;` is enough of an implementation. == close(fd) Close a file descriptor. == getrusage(RUSAGE_SELF, ptr) gcc is rather eager to know how long it's taking. We can probably stub this out safely. == sysinfo(ptr) I'm honestly not sure why gcc reads this, but we can probably stub it out. == umask(mask) Thread-unsafe, but we should probably bail if this gets invoked while multithreaded. We just `mode &= ~mask` any filesystem call, and that's the only place this matters. == prlimit(0, resource, NULL, ptr) Retrieve a resource limit. We can stub all of these out. === prlimit64(0, RLIMIT_STACK, NULL, ptr) Retrieve the maximum stack size, presumably specifically of the main thread. === prlimit64(0, RLIMIT_AS, NULL, ptr) Retrieve the maximum virtual memory size. === prlimit64(0, RLIMIT_RSS, NULL, ptr) The maximum amount of resident memory. === prlimit64(0, RLIMIT_NOFILE, NULL, ptr) The maximum amount of file descriptors. = Easy == brk Should be fairly trivial. `validate_prctl_map_addr` documents the requirements on address space layout. == exit_group(status) Kill the process, aka thread group. Straightforward enough, although we do need to emit `SIGCHLD` appropriately. == fcntl(fd, F_GETFD) Grab the current flags for an fd. Used only immediately preceding `fcntl(fd, F_SETFD, FD_CLOEXEC)`. == fcntl(fd, F_SETFD, FD_CLOEXEC) Set the `CLOEXEC` flag. = This is where they start to trick you == set_robust_list The code for this itself isn't complex (we just store a pointer), but we have to actually do futex signalling on process death and execve. Technically trivial if `futex` is never called. == set_tid_address The code for this itself isn't complex (we just store a pointer), but we have to actually do futex signalling on thread termination. Technically trivial if `futex` is never called. == getcwd(buf, len) Read the current working directory path into a buffer. Equivalent to `readlink("/proc/self/cwd", buf, len)`. Probably bail if anything funny happens. == readlink(path, buf, len) Read the target of a symlink. == unlink(path) Remove a directory entry that is itself not a directory. Equivalent to `unlinkat(AT_FDCWD, path, 0)`. == chmod(path, mode) Change the mode of an inode. == pipe2(fds_out, flags) Technically easy, but almost certainly being invoked for imminent IPC. == read(fd, ptr, len) Read bytes from a file descriptor. Hard if it's IPC, easier if it's filesystem I/O. == lseek(fd, offset, SEEK_SET) Reposition the file offset, relative to the start of the file. == lseek(fd, offset, SEEK_CUR) Reposition the file offset, relative to the current offset. == pread64(fd, buf, len, offset) Equivalent to atomic `lseek(fd, offset, SEEK_SET); read(fd, buf, len)`, but without the side effects on the file descriptor offset. == write(fd, ptr, len) Write bytes to a file descriptor. Hard if it's IPC, easier if it's filesystem I/O. == execve(pathname, argv, envp) Replace the current process image with another, loaded from a file. Technically easy, modulo `O_CLOEXEC` handling, but almost certainly spells imminent IPC. == access(path, mode) Equivalent to atomic `int fd = open(path, mode); if (fd >= 0) close(fd);`, except if `eugid != ugid`. Build systems are rarely setuid, so this distinction seems ok to bail on. == openat(AT_FDCWD, path, flags, mode) Filesystem I/O. = This one's hard == newfstatat(dirfd, name, stat_out, flag) Filesystem I/O, primarily complicated by mtime and inode numbers. == vfork() Strictly less troubling than fork, but this spells imminent IPC. == wait4(wstatus, 0, NULL) Pure IPC. This probably isn't much trouble if nothing unusual happens, however. == rt_sigaction Signals are complicated, underspecified, *and* IPC. This is going to hurt. == rt_sigprocmask Signal mask manipulation is a doozy, but unblocking signals can deliver queued signals…