From 977730017ce27275b71d29dfa88e98ca4db21dcd Mon Sep 17 00:00:00 2001 From: edef Date: Mon, 27 Dec 2021 20:41:43 +0000 Subject: ripple/website/pages/syscalls: document the syscalls we need to support for our MVP Change-Id: I651816d004ee5c5049569ddcf157d492cbcc0b2a --- ripple/website/pages/syscalls.adoc | 174 +++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 ripple/website/pages/syscalls.adoc (limited to 'ripple') diff --git a/ripple/website/pages/syscalls.adoc b/ripple/website/pages/syscalls.adoc new file mode 100644 index 0000000..5b1cf69 --- /dev/null +++ b/ripple/website/pages/syscalls.adoc @@ -0,0 +1,174 @@ += 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… -- cgit 1.4.1