diff options
author | Andreas Kling <awesomekling@gmail.com> | 2020-01-11 20:48:43 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2020-01-11 20:48:43 +0100 |
commit | 409a4f775642f0a036905dae22d5010da79c3969 (patch) | |
tree | 904548d732ebb0e810879eba667615fef56e961c | |
parent | 41c504a33becea8aa9b437cd3c0dc312b2bf1fe9 (diff) | |
download | serenity-409a4f775642f0a036905dae22d5010da79c3969.zip |
ping: Use pledge()
-rw-r--r-- | Kernel/Process.cpp | 242 | ||||
-rw-r--r-- | Kernel/Process.h | 31 | ||||
-rw-r--r-- | Kernel/Syscall.h | 8 | ||||
-rw-r--r-- | Userland/ping.cpp | 15 |
4 files changed, 295 insertions, 1 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 38b6933edd..83c58611c3 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -53,6 +53,26 @@ //#define SIGNAL_DEBUG //#define SHARED_BUFFER_DEBUG +#define REQUIRE_NO_PROMISES \ + do { \ + if (has_promises()) { \ + dbg() << *current << " has made a promise"; \ + cli(); \ + crash(SIGABRT, 0); \ + ASSERT_NOT_REACHED(); \ + } \ + } while (0) + +#define REQUIRE_PROMISE(promise) \ + do { \ + if (has_promises() && !has_promised(Pledge::promise)) { \ + dbg() << *current << " has not pledged " << #promise; \ + cli(); \ + crash(SIGABRT, 0); \ + ASSERT_NOT_REACHED(); \ + } \ + } while (0) + static void create_signal_trampolines(); static void create_kernel_info_page(); @@ -212,6 +232,8 @@ Region* Process::region_containing(const Range& range) int Process::sys$set_mmap_name(const Syscall::SC_set_mmap_name_params* user_params) { + REQUIRE_PROMISE(stdio); + if (!validate_read_typed(user_params)) return -EFAULT; @@ -281,6 +303,8 @@ Vector<Region*, 2> Process::split_region_around_range(const Region& source_regio void* Process::sys$mmap(const Syscall::SC_mmap_params* user_params) { + REQUIRE_PROMISE(stdio); + if (!validate_read_typed(user_params)) return (void*)-EFAULT; @@ -383,6 +407,7 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* user_params) int Process::sys$munmap(void* addr, size_t size) { + REQUIRE_PROMISE(stdio); Range range_to_unmap { VirtualAddress((u32)addr), size }; if (auto* whole_region = region_from_range(range_to_unmap)) { if (!whole_region->is_mmap()) @@ -419,6 +444,7 @@ int Process::sys$munmap(void* addr, size_t size) int Process::sys$mprotect(void* addr, size_t size, int prot) { + REQUIRE_PROMISE(stdio); Range range_to_mprotect = { VirtualAddress((u32)addr), size }; if (auto* whole_region = region_from_range(range_to_mprotect)) { @@ -481,6 +507,7 @@ int Process::sys$mprotect(void* addr, size_t size, int prot) int Process::sys$madvise(void* address, size_t size, int advice) { + REQUIRE_PROMISE(stdio); auto* region = region_from_range({ VirtualAddress((u32)address), size }); if (!region) return -EINVAL; @@ -517,6 +544,7 @@ int Process::sys$madvise(void* address, size_t size, int advice) int Process::sys$purge(int mode) { + REQUIRE_NO_PROMISES; if (!is_superuser()) return -EPERM; int purged_page_count = 0; @@ -553,6 +581,7 @@ int Process::sys$purge(int mode) int Process::sys$gethostname(char* buffer, ssize_t size) { + REQUIRE_PROMISE(stdio); if (size < 0) return -EINVAL; if (!validate_write(buffer, size)) @@ -566,6 +595,7 @@ int Process::sys$gethostname(char* buffer, ssize_t size) pid_t Process::sys$fork(RegisterDump& regs) { + REQUIRE_PROMISE(proc); Thread* child_first_thread = nullptr; auto* child = new Process(child_first_thread, m_name, m_uid, m_gid, m_pid, m_ring, m_cwd, m_executable, m_tty, this); child->m_root_directory = m_root_directory; @@ -747,6 +777,8 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir m_elf_loader = move(loader); m_executable = description->custody(); + m_promises = m_execpromises; + // Copy of the master TLS region that we will clone for new threads m_master_tls_region = master_tls_region; @@ -914,6 +946,7 @@ int Process::exec(String path, Vector<String> arguments, Vector<String> environm int Process::sys$execve(const Syscall::SC_execve_params* user_params) { + REQUIRE_PROMISE(exec); // NOTE: Be extremely careful with allocating any kernel memory in exec(). // On success, the kernel stack will be lost. Syscall::SC_execve_params params; @@ -1258,6 +1291,7 @@ int Process::fd_flags(int fd) const ssize_t Process::sys$get_dir_entries(int fd, void* buffer, ssize_t size) { + REQUIRE_PROMISE(stdio); if (size < 0) return -EINVAL; if (!validate_write(buffer, size)) @@ -1270,6 +1304,7 @@ ssize_t Process::sys$get_dir_entries(int fd, void* buffer, ssize_t size) int Process::sys$lseek(int fd, off_t offset, int whence) { + REQUIRE_PROMISE(stdio); auto description = file_description(fd); if (!description) return -EBADF; @@ -1278,6 +1313,7 @@ int Process::sys$lseek(int fd, off_t offset, int whence) int Process::sys$ttyname_r(int fd, char* buffer, ssize_t size) { + REQUIRE_PROMISE(tty); if (size < 0) return -EINVAL; if (!validate_write(buffer, size)) @@ -1296,6 +1332,7 @@ int Process::sys$ttyname_r(int fd, char* buffer, ssize_t size) int Process::sys$ptsname_r(int fd, char* buffer, ssize_t size) { + REQUIRE_PROMISE(tty); if (size < 0) return -EINVAL; if (!validate_write(buffer, size)) @@ -1315,6 +1352,7 @@ int Process::sys$ptsname_r(int fd, char* buffer, ssize_t size) ssize_t Process::sys$writev(int fd, const struct iovec* iov, int iov_count) { + REQUIRE_PROMISE(stdio); if (iov_count < 0) return -EINVAL; @@ -1400,6 +1438,7 @@ ssize_t Process::do_write(FileDescription& description, const u8* data, int data ssize_t Process::sys$write(int fd, const u8* data, ssize_t size) { + REQUIRE_PROMISE(stdio); if (size < 0) return -EINVAL; if (size == 0) @@ -1420,6 +1459,7 @@ ssize_t Process::sys$write(int fd, const u8* data, ssize_t size) ssize_t Process::sys$read(int fd, u8* buffer, ssize_t size) { + REQUIRE_PROMISE(stdio); if (size < 0) return -EINVAL; if (size == 0) @@ -1447,6 +1487,7 @@ ssize_t Process::sys$read(int fd, u8* buffer, ssize_t size) int Process::sys$close(int fd) { + REQUIRE_PROMISE(stdio); auto description = file_description(fd); #ifdef DEBUG_IO dbgprintf("%s(%u) sys$close(%d) %p\n", name().characters(), pid(), fd, description.ptr()); @@ -1460,6 +1501,7 @@ int Process::sys$close(int fd) int Process::sys$utime(const char* user_path, size_t path_length, const utimbuf* user_buf) { + REQUIRE_PROMISE(fattr); if (user_buf && !validate_read_typed(user_buf)) return -EFAULT; auto path = get_syscall_path_argument(user_path, path_length); @@ -1477,6 +1519,7 @@ int Process::sys$utime(const char* user_path, size_t path_length, const utimbuf* int Process::sys$access(const char* user_path, size_t path_length, int mode) { + REQUIRE_PROMISE(rpath); auto path = get_syscall_path_argument(user_path, path_length); if (path.is_error()) return path.error(); @@ -1485,6 +1528,7 @@ int Process::sys$access(const char* user_path, size_t path_length, int mode) int Process::sys$fcntl(int fd, int cmd, u32 arg) { + REQUIRE_PROMISE(stdio); (void)cmd; (void)arg; dbgprintf("sys$fcntl: fd=%d, cmd=%d, arg=%u\n", fd, cmd, arg); @@ -1522,6 +1566,7 @@ int Process::sys$fcntl(int fd, int cmd, u32 arg) int Process::sys$fstat(int fd, stat* statbuf) { + REQUIRE_PROMISE(stdio); if (!validate_write_typed(statbuf)) return -EFAULT; auto description = file_description(fd); @@ -1532,6 +1577,7 @@ int Process::sys$fstat(int fd, stat* statbuf) int Process::sys$lstat(const char* user_path, size_t path_length, stat* user_statbuf) { + REQUIRE_PROMISE(rpath); if (!validate_write_typed(user_statbuf)) return -EFAULT; auto path = get_syscall_path_argument(user_path, path_length); @@ -1550,6 +1596,7 @@ int Process::sys$lstat(const char* user_path, size_t path_length, stat* user_sta int Process::sys$stat(const char* user_path, size_t path_length, stat* user_statbuf) { + REQUIRE_PROMISE(rpath); if (!validate_write_typed(user_statbuf)) return -EFAULT; auto path = get_syscall_path_argument(user_path, path_length); @@ -1594,6 +1641,7 @@ String Process::validate_and_copy_string_from_user(const Syscall::StringArgument int Process::sys$readlink(const Syscall::SC_readlink_params* user_params) { + REQUIRE_PROMISE(rpath); if (!validate_read_typed(user_params)) return -EFAULT; Syscall::SC_readlink_params params; @@ -1627,6 +1675,7 @@ int Process::sys$readlink(const Syscall::SC_readlink_params* user_params) int Process::sys$chdir(const char* user_path, size_t path_length) { + REQUIRE_PROMISE(rpath); auto path = get_syscall_path_argument(user_path, path_length); if (path.is_error()) return path.error(); @@ -1639,6 +1688,7 @@ int Process::sys$chdir(const char* user_path, size_t path_length) int Process::sys$fchdir(int fd) { + REQUIRE_PROMISE(stdio); auto description = file_description(fd); if (!description) return -EBADF; @@ -1655,6 +1705,7 @@ int Process::sys$fchdir(int fd) int Process::sys$getcwd(char* buffer, ssize_t size) { + REQUIRE_PROMISE(rpath); if (size < 0) return -EINVAL; if (!validate_write(buffer, size)) @@ -1686,6 +1737,14 @@ int Process::sys$open(const Syscall::SC_open_params* user_params) auto options = params.options; auto mode = params.mode; + if ((options & O_RDWR) || (options & O_WRONLY)) + REQUIRE_PROMISE(wpath); + else + REQUIRE_PROMISE(rpath); + + if (options & O_CREAT) + REQUIRE_PROMISE(cpath); + auto path = get_syscall_path_argument(params.path); if (path.is_error()) return path.error(); @@ -1721,6 +1780,14 @@ int Process::sys$openat(const Syscall::SC_openat_params* user_params) int options = params.options; u16 mode = params.mode; + if ((options & O_RDWR) || (options & O_WRONLY)) + REQUIRE_PROMISE(wpath); + else + REQUIRE_PROMISE(rpath); + + if (options & O_CREAT) + REQUIRE_PROMISE(cpath); + // Ignore everything except permission bits. mode &= 04777; @@ -1773,6 +1840,7 @@ int Process::alloc_fd(int first_candidate_fd) int Process::sys$pipe(int pipefd[2], int flags) { + REQUIRE_PROMISE(stdio); if (!validate_write_typed(pipefd)) return -EFAULT; if (number_of_open_file_descriptors() + 2 > max_open_file_descriptors()) @@ -1799,6 +1867,7 @@ int Process::sys$pipe(int pipefd[2], int flags) int Process::sys$killpg(int pgrp, int signum) { + REQUIRE_PROMISE(proc); if (signum < 1 || signum >= 32) return -EINVAL; if (pgrp < 0) @@ -1810,6 +1879,7 @@ int Process::sys$killpg(int pgrp, int signum) int Process::sys$setuid(uid_t uid) { + REQUIRE_PROMISE(id); if (uid != m_uid && !is_superuser()) return -EPERM; m_uid = uid; @@ -1819,6 +1889,7 @@ int Process::sys$setuid(uid_t uid) int Process::sys$setgid(gid_t gid) { + REQUIRE_PROMISE(id); if (gid != m_gid && !is_superuser()) return -EPERM; m_gid = gid; @@ -1828,6 +1899,7 @@ int Process::sys$setgid(gid_t gid) unsigned Process::sys$alarm(unsigned seconds) { + REQUIRE_PROMISE(stdio); unsigned previous_alarm_remaining = 0; if (m_alarm_deadline && m_alarm_deadline > g_uptime) { previous_alarm_remaining = (m_alarm_deadline - g_uptime) / TICKS_PER_SECOND; @@ -1842,6 +1914,7 @@ unsigned Process::sys$alarm(unsigned seconds) int Process::sys$uname(utsname* buf) { + REQUIRE_PROMISE(stdio); if (!validate_write_typed(buf)) return -EFAULT; LOCKER(*s_hostname_lock); @@ -1905,6 +1978,7 @@ KResult Process::do_killpg(pid_t pgrp, int signal) int Process::sys$kill(pid_t pid, int signal) { + REQUIRE_PROMISE(proc); if (signal < 0 || signal >= 32) return -EINVAL; if (pid <= 0) @@ -1931,6 +2005,7 @@ int Process::sys$kill(pid_t pid, int signal) int Process::sys$usleep(useconds_t usec) { + REQUIRE_PROMISE(stdio); if (!usec) return 0; u64 wakeup_time = current->sleep(usec / 1000); @@ -1941,6 +2016,7 @@ int Process::sys$usleep(useconds_t usec) int Process::sys$sleep(unsigned seconds) { + REQUIRE_PROMISE(stdio); if (!seconds) return 0; u64 wakeup_time = current->sleep(seconds * TICKS_PER_SECOND); @@ -1963,6 +2039,7 @@ void kgettimeofday(timeval& tv) int Process::sys$gettimeofday(timeval* tv) { + REQUIRE_PROMISE(stdio); if (!validate_write_typed(tv)) return -EFAULT; *tv = kgettimeofday(); @@ -1971,36 +2048,43 @@ int Process::sys$gettimeofday(timeval* tv) uid_t Process::sys$getuid() { + REQUIRE_PROMISE(stdio); return m_uid; } gid_t Process::sys$getgid() { + REQUIRE_PROMISE(stdio); return m_gid; } uid_t Process::sys$geteuid() { + REQUIRE_PROMISE(stdio); return m_euid; } gid_t Process::sys$getegid() { + REQUIRE_PROMISE(stdio); return m_egid; } pid_t Process::sys$getpid() { + REQUIRE_PROMISE(stdio); return m_pid; } pid_t Process::sys$getppid() { + REQUIRE_PROMISE(stdio); return m_ppid; } mode_t Process::sys$umask(mode_t mask) { + REQUIRE_PROMISE(stdio); auto old_mask = m_umask; m_umask = mask & 0777; return old_mask; @@ -2031,6 +2115,7 @@ int Process::reap(Process& process) pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options) { + REQUIRE_PROMISE(stdio); dbgprintf("sys$waitpid(%d, %p, %d)\n", waitee, wstatus, options); if (!options) { @@ -2139,6 +2224,7 @@ bool Process::validate_write(void* address, ssize_t size) const pid_t Process::sys$getsid(pid_t pid) { + REQUIRE_PROMISE(stdio); if (pid == 0) return m_sid; InterruptDisabler disabler; @@ -2152,6 +2238,7 @@ pid_t Process::sys$getsid(pid_t pid) pid_t Process::sys$setsid() { + REQUIRE_PROMISE(proc); InterruptDisabler disabler; bool found_process_with_same_pgid_as_my_pid = false; Process::for_each_in_pgrp(pid(), [&](auto&) { @@ -2167,6 +2254,7 @@ pid_t Process::sys$setsid() pid_t Process::sys$getpgid(pid_t pid) { + REQUIRE_PROMISE(stdio); if (pid == 0) return m_pgid; InterruptDisabler disabler; // FIXME: Use a ProcessHandle @@ -2178,6 +2266,7 @@ pid_t Process::sys$getpgid(pid_t pid) pid_t Process::sys$getpgrp() { + REQUIRE_PROMISE(stdio); return m_pgid; } @@ -2192,6 +2281,7 @@ static pid_t get_sid_from_pgid(pid_t pgid) int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid) { + REQUIRE_PROMISE(proc); InterruptDisabler disabler; // FIXME: Use a ProcessHandle pid_t pid = specified_pid ? specified_pid : m_pid; if (specified_pgid < 0) { @@ -2240,11 +2330,13 @@ int Process::sys$ioctl(int fd, unsigned request, unsigned arg) int Process::sys$getdtablesize() { + REQUIRE_PROMISE(stdio); return m_max_open_file_descriptors; } int Process::sys$dup(int old_fd) { + REQUIRE_PROMISE(stdio); auto description = file_description(old_fd); if (!description) return -EBADF; @@ -2257,6 +2349,7 @@ int Process::sys$dup(int old_fd) int Process::sys$dup2(int old_fd, int new_fd) { + REQUIRE_PROMISE(stdio); auto description = file_description(old_fd); if (!description) return -EBADF; @@ -2268,6 +2361,7 @@ int Process::sys$dup2(int old_fd, int new_fd) int Process::sys$sigprocmask(int how, const sigset_t* set, sigset_t* old_set) { + REQUIRE_PROMISE(stdio); if (old_set) { if (!validate_write_typed(old_set)) return -EFAULT; @@ -2297,6 +2391,7 @@ int Process::sys$sigprocmask(int how, const sigset_t* set, sigset_t* old_set) int Process::sys$sigpending(sigset_t* set) { + REQUIRE_PROMISE(stdio); if (!validate_write_typed(set)) return -EFAULT; copy_to_user(set, ¤t->m_pending_signals, sizeof(current->m_pending_signals)); @@ -2305,6 +2400,7 @@ int Process::sys$sigpending(sigset_t* set) int Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act) { + REQUIRE_PROMISE(stdio); if (signum < 1 || signum >= 32 || signum == SIGKILL || signum == SIGSTOP) return -EINVAL; if (!validate_read_typed(act)) @@ -2324,6 +2420,7 @@ int Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act) int Process::sys$getgroups(ssize_t count, gid_t* gids) { + REQUIRE_PROMISE(stdio); if (count < 0) return -EINVAL; if (!count) @@ -2341,6 +2438,7 @@ int Process::sys$getgroups(ssize_t count, gid_t* gids) int Process::sys$setgroups(ssize_t count, const gid_t* gids) { + REQUIRE_PROMISE(id); if (count < 0) return -EINVAL; if (!is_superuser()) @@ -2359,6 +2457,7 @@ int Process::sys$setgroups(ssize_t count, const gid_t* gids) int Process::sys$mkdir(const char* user_path, size_t path_length, mode_t mode) { + REQUIRE_PROMISE(cpath); auto path = get_syscall_path_argument(user_path, path_length); if (path.is_error()) return path.error(); @@ -2367,6 +2466,7 @@ int Process::sys$mkdir(const char* user_path, size_t path_length, mode_t mode) int Process::sys$realpath(const Syscall::SC_realpath_params* user_params) { + REQUIRE_PROMISE(rpath); if (!validate_read_typed(user_params)) return -EFAULT; @@ -2401,6 +2501,7 @@ int Process::sys$realpath(const Syscall::SC_realpath_params* user_params) clock_t Process::sys$times(tms* times) { + REQUIRE_PROMISE(stdio); if (!validate_write_typed(times)) return -EFAULT; copy_to_user(×->tms_utime, &m_ticks_in_user, sizeof(m_ticks_in_user)); @@ -2412,6 +2513,7 @@ clock_t Process::sys$times(tms* times) int Process::sys$select(const Syscall::SC_select_params* params) { + REQUIRE_PROMISE(stdio); // FIXME: Return -EINVAL if timeout is invalid. if (!validate_read_typed(params)) return -EFAULT; @@ -2498,6 +2600,7 @@ int Process::sys$select(const Syscall::SC_select_params* params) int Process::sys$poll(pollfd* fds, int nfds, int timeout) { + REQUIRE_PROMISE(stdio); if (!validate_read_typed(fds)) return -EFAULT; @@ -2567,6 +2670,7 @@ Custody& Process::current_directory() int Process::sys$link(const Syscall::SC_link_params* user_params) { + REQUIRE_PROMISE(cpath); if (!validate_read_typed(user_params)) return -EFAULT; Syscall::SC_link_params params; @@ -2580,6 +2684,7 @@ int Process::sys$link(const Syscall::SC_link_params* user_params) int Process::sys$unlink(const char* user_path, size_t path_length) { + REQUIRE_PROMISE(cpath); if (!validate_read(user_path, path_length)) return -EFAULT; auto path = get_syscall_path_argument(user_path, path_length); @@ -2590,6 +2695,7 @@ int Process::sys$unlink(const char* user_path, size_t path_length) int Process::sys$symlink(const Syscall::SC_symlink_params* user_params) { + REQUIRE_PROMISE(cpath); if (!validate_read_typed(user_params)) return -EFAULT; Syscall::SC_symlink_params params; @@ -2621,6 +2727,7 @@ KResultOr<String> Process::get_syscall_path_argument(const Syscall::StringArgume int Process::sys$rmdir(const char* user_path, size_t path_length) { + REQUIRE_PROMISE(cpath); auto path = get_syscall_path_argument(user_path, path_length); if (path.is_error()) return path.error(); @@ -2629,6 +2736,7 @@ int Process::sys$rmdir(const char* user_path, size_t path_length) int Process::sys$chmod(const char* user_path, size_t path_length, mode_t mode) { + REQUIRE_PROMISE(fattr); auto path = get_syscall_path_argument(user_path, path_length); if (path.is_error()) return path.error(); @@ -2637,6 +2745,7 @@ int Process::sys$chmod(const char* user_path, size_t path_length, mode_t mode) int Process::sys$fchmod(int fd, mode_t mode) { + REQUIRE_PROMISE(fattr); auto description = file_description(fd); if (!description) return -EBADF; @@ -2645,6 +2754,7 @@ int Process::sys$fchmod(int fd, mode_t mode) int Process::sys$fchown(int fd, uid_t uid, gid_t gid) { + REQUIRE_PROMISE(chown); auto description = file_description(fd); if (!description) return -EBADF; @@ -2653,6 +2763,7 @@ int Process::sys$fchown(int fd, uid_t uid, gid_t gid) int Process::sys$chown(const Syscall::SC_chown_params* user_params) { + REQUIRE_PROMISE(chown); if (!validate_read_typed(user_params)) return -EFAULT; Syscall::SC_chown_params params; @@ -2790,8 +2901,18 @@ size_t Process::amount_purgeable_nonvolatile() const return amount; } +#define REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain) \ + do { \ + if (domain == AF_INET) \ + REQUIRE_PROMISE(inet); \ + else if (domain == AF_LOCAL) \ + REQUIRE_PROMISE(unix); \ + } while (0) + int Process::sys$socket(int domain, int type, int protocol) { + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain); + if ((type & SOCK_TYPE_MASK) == SOCK_RAW && !is_superuser()) return -EACCES; int fd = alloc_fd(); @@ -2822,6 +2943,7 @@ int Process::sys$bind(int sockfd, const sockaddr* address, socklen_t address_len if (!description->is_socket()) return -ENOTSOCK; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); return socket.bind(address, address_length); } @@ -2833,6 +2955,7 @@ int Process::sys$listen(int sockfd, int backlog) if (!description->is_socket()) return -ENOTSOCK; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); if (socket.is_connected()) return -EINVAL; return socket.listen(backlog); @@ -2854,6 +2977,7 @@ int Process::sys$accept(int accepting_socket_fd, sockaddr* address, socklen_t* a if (!accepting_socket_description->is_socket()) return -ENOTSOCK; auto& socket = *accepting_socket_description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); if (!socket.can_accept()) { if (accepting_socket_description->is_blocking()) { if (current->block<Thread::AcceptBlocker>(*accepting_socket_description) != Thread::BlockResult::WokeNormally) @@ -2893,6 +3017,7 @@ int Process::sys$connect(int sockfd, const sockaddr* address, socklen_t address_ return -ENOTSOCK; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); SmapDisabler disabler; return socket.connect(*description, address, address_size, description->is_blocking() ? ShouldBlock::Yes : ShouldBlock::No); } @@ -2920,6 +3045,7 @@ ssize_t Process::sys$sendto(const Syscall::SC_sendto_params* user_params) return -ENOTSOCK; SmapDisabler disabler; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); return socket.sendto(*description, params.data.data, params.data.size, flags, addr, addr_length); } @@ -2952,6 +3078,7 @@ ssize_t Process::sys$recvfrom(const Syscall::SC_recvfrom_params* user_params) if (!description->is_socket()) return -ENOTSOCK; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); bool original_blocking = description->is_blocking(); if (flags & MSG_DONTWAIT) @@ -2984,6 +3111,7 @@ int Process::sys$getsockname(int sockfd, sockaddr* addr, socklen_t* addrlen) return -ENOTSOCK; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); if (!socket.get_local_address(addr, addrlen)) return -EINVAL; // FIXME: Should this be another error? I'm not sure. @@ -3011,6 +3139,7 @@ int Process::sys$getpeername(int sockfd, sockaddr* addr, socklen_t* addrlen) return -ENOTSOCK; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); if (socket.setup_state() != Socket::SetupState::Completed) return -ENOTCONN; @@ -3023,6 +3152,7 @@ int Process::sys$getpeername(int sockfd, sockaddr* addr, socklen_t* addrlen) int Process::sys$sched_setparam(pid_t pid, const struct sched_param* param) { + REQUIRE_PROMISE(proc); if (!validate_read_typed(param)) return -EFAULT; @@ -3049,6 +3179,7 @@ int Process::sys$sched_setparam(pid_t pid, const struct sched_param* param) int Process::sys$sched_getparam(pid_t pid, struct sched_param* param) { + REQUIRE_PROMISE(proc); if (!validate_write_typed(param)) return -EFAULT; @@ -3092,6 +3223,7 @@ int Process::sys$getsockopt(const Syscall::SC_getsockopt_params* params) if (!description->is_socket()) return -ENOTSOCK; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); return socket.getsockopt(*description, level, option, value, value_size); } @@ -3116,6 +3248,7 @@ int Process::sys$setsockopt(const Syscall::SC_setsockopt_params* params) if (!description->is_socket()) return -ENOTSOCK; auto& socket = *description->socket(); + REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); return socket.setsockopt(level, option, value, value_size); } @@ -3131,6 +3264,7 @@ void Process::disown_all_shared_buffers() int Process::sys$create_shared_buffer(int size, void** buffer) { + REQUIRE_PROMISE(shared_buffer); if (!size || size < 0) return -EINVAL; size = PAGE_ROUND_UP(size); @@ -3159,6 +3293,7 @@ int Process::sys$create_shared_buffer(int size, void** buffer) int Process::sys$share_buffer_with(int shared_buffer_id, pid_t peer_pid) { + REQUIRE_PROMISE(shared_buffer); if (!peer_pid || peer_pid < 0 || peer_pid == m_pid) return -EINVAL; LOCKER(shared_buffers().lock()); @@ -3180,6 +3315,7 @@ int Process::sys$share_buffer_with(int shared_buffer_id, pid_t peer_pid) int Process::sys$share_buffer_globally(int shared_buffer_id) { + REQUIRE_PROMISE(shared_buffer); LOCKER(shared_buffers().lock()); auto it = shared_buffers().resource().find(shared_buffer_id); if (it == shared_buffers().resource().end()) @@ -3193,6 +3329,7 @@ int Process::sys$share_buffer_globally(int shared_buffer_id) int Process::sys$release_shared_buffer(int shared_buffer_id) { + REQUIRE_PROMISE(shared_buffer); LOCKER(shared_buffers().lock()); auto it = shared_buffers().resource().find(shared_buffer_id); if (it == shared_buffers().resource().end()) @@ -3209,6 +3346,7 @@ int Process::sys$release_shared_buffer(int shared_buffer_id) void* Process::sys$get_shared_buffer(int shared_buffer_id) { + REQUIRE_PROMISE(shared_buffer); LOCKER(shared_buffers().lock()); auto it = shared_buffers().resource().find(shared_buffer_id); if (it == shared_buffers().resource().end()) @@ -3224,6 +3362,7 @@ void* Process::sys$get_shared_buffer(int shared_buffer_id) int Process::sys$seal_shared_buffer(int shared_buffer_id) { + REQUIRE_PROMISE(shared_buffer); LOCKER(shared_buffers().lock()); auto it = shared_buffers().resource().find(shared_buffer_id); if (it == shared_buffers().resource().end()) @@ -3240,6 +3379,7 @@ int Process::sys$seal_shared_buffer(int shared_buffer_id) int Process::sys$get_shared_buffer_size(int shared_buffer_id) { + REQUIRE_PROMISE(shared_buffer); LOCKER(shared_buffers().lock()); auto it = shared_buffers().resource().find(shared_buffer_id); if (it == shared_buffers().resource().end()) @@ -3255,6 +3395,7 @@ int Process::sys$get_shared_buffer_size(int shared_buffer_id) int Process::sys$set_shared_buffer_volatile(int shared_buffer_id, bool state) { + REQUIRE_PROMISE(shared_buffer); LOCKER(shared_buffers().lock()); auto it = shared_buffers().resource().find(shared_buffer_id); if (it == shared_buffers().resource().end()) @@ -3296,6 +3437,7 @@ void Process::send_signal(u8 signal, Process* sender) int Process::sys$create_thread(void* (*entry)(void*), void* argument, const Syscall::SC_create_thread_params* params) { + REQUIRE_PROMISE(thread); if (!validate_read((const void*)entry, sizeof(void*))) return -EFAULT; @@ -3357,6 +3499,7 @@ int Process::sys$create_thread(void* (*entry)(void*), void* argument, const Sysc void Process::sys$exit_thread(void* exit_value) { + REQUIRE_PROMISE(thread); cli(); current->m_exit_value = exit_value; current->set_should_die(); @@ -3367,6 +3510,7 @@ void Process::sys$exit_thread(void* exit_value) int Process::sys$detach_thread(int tid) { + REQUIRE_PROMISE(thread); auto* thread = Thread::from_tid(tid); if (!thread || thread->pid() != pid()) return -ESRCH; @@ -3380,6 +3524,7 @@ int Process::sys$detach_thread(int tid) int Process::sys$join_thread(int tid, void** exit_value) { + REQUIRE_PROMISE(thread); if (exit_value && !validate_write_typed(exit_value)) return -EFAULT; @@ -3425,6 +3570,7 @@ int Process::sys$join_thread(int tid, void** exit_value) int Process::sys$set_thread_name(int tid, const char* user_name, size_t user_name_length) { + REQUIRE_PROMISE(thread); auto name = validate_and_copy_string_from_user(user_name, user_name_length); if (name.is_null()) return -EFAULT; @@ -3442,6 +3588,7 @@ int Process::sys$set_thread_name(int tid, const char* user_name, size_t user_nam } int Process::sys$get_thread_name(int tid, char* buffer, size_t buffer_size) { + REQUIRE_PROMISE(thread); if (buffer_size == 0) return -EINVAL; @@ -3461,11 +3608,13 @@ int Process::sys$get_thread_name(int tid, char* buffer, size_t buffer_size) int Process::sys$gettid() { + REQUIRE_PROMISE(stdio); return current->tid(); } int Process::sys$donate(int tid) { + REQUIRE_PROMISE(stdio); if (tid < 0) return -EINVAL; InterruptDisabler disabler; @@ -3478,6 +3627,7 @@ int Process::sys$donate(int tid) int Process::sys$rename(const Syscall::SC_rename_params* user_params) { + REQUIRE_PROMISE(cpath); if (!validate_read_typed(user_params)) return -EFAULT; Syscall::SC_rename_params params; @@ -3493,6 +3643,7 @@ int Process::sys$rename(const Syscall::SC_rename_params* user_params) int Process::sys$ftruncate(int fd, off_t length) { + REQUIRE_PROMISE(stdio); if (length < 0) return -EINVAL; auto description = file_description(fd); @@ -3505,6 +3656,7 @@ int Process::sys$ftruncate(int fd, off_t length) int Process::sys$watch_file(const char* user_path, size_t path_length) { + REQUIRE_PROMISE(rpath); auto path = get_syscall_path_argument(user_path, path_length); if (path.is_error()) return path.error(); @@ -3530,6 +3682,7 @@ int Process::sys$watch_file(const char* user_path, size_t path_length) int Process::sys$systrace(pid_t pid) { + REQUIRE_PROMISE(proc); InterruptDisabler disabler; auto* peer = Process::from_pid(pid); if (!peer) @@ -3550,6 +3703,8 @@ int Process::sys$halt() if (!is_superuser()) return -EPERM; + REQUIRE_NO_PROMISES; + dbgprintf("acquiring FS locks...\n"); FS::lock_all(); dbgprintf("syncing mounted filesystems...\n"); @@ -3565,6 +3720,8 @@ int Process::sys$reboot() if (!is_superuser()) return -EPERM; + REQUIRE_NO_PROMISES; + dbgprintf("acquiring FS locks...\n"); FS::lock_all(); dbgprintf("syncing mounted filesystems...\n"); @@ -3580,6 +3737,8 @@ int Process::sys$mount(const Syscall::SC_mount_params* user_params) if (!is_superuser()) return -EPERM; + REQUIRE_NO_PROMISES; + if (!validate_read_typed(user_params)) return -EFAULT; Syscall::SC_mount_params params; @@ -3660,6 +3819,8 @@ int Process::sys$umount(const char* user_mountpoint, size_t mountpoint_length) if (!is_superuser()) return -EPERM; + REQUIRE_NO_PROMISES; + if (!validate_read(user_mountpoint, mountpoint_length)) return -EFAULT; @@ -3696,6 +3857,7 @@ void Process::FileDescriptionAndFlags::set(NonnullRefPtr<FileDescription>&& d, u int Process::sys$mknod(const Syscall::SC_mknod_params* user_params) { + REQUIRE_PROMISE(dpath); if (!validate_read_typed(user_params)) return -EFAULT; Syscall::SC_mknod_params params; @@ -3745,6 +3907,7 @@ KBuffer Process::backtrace(ProcessInspectionHandle& handle) const int Process::sys$set_process_icon(int icon_id) { + REQUIRE_PROMISE(shared_buffer); LOCKER(shared_buffers().lock()); auto it = shared_buffers().resource().find(icon_id); if (it == shared_buffers().resource().end()) @@ -3758,6 +3921,7 @@ int Process::sys$set_process_icon(int icon_id) int Process::sys$get_process_name(char* buffer, int buffer_size) { + REQUIRE_PROMISE(stdio); if (buffer_size <= 0) return -EINVAL; @@ -3791,6 +3955,8 @@ int Process::sys$setkeymap(const Syscall::SC_setkeymap_params* params) if (!is_superuser()) return -EPERM; + REQUIRE_NO_PROMISES; + if (!validate_read_typed(params)) return -EFAULT; @@ -3814,6 +3980,7 @@ int Process::sys$setkeymap(const Syscall::SC_setkeymap_params* params) int Process::sys$clock_gettime(clockid_t clock_id, timespec* ts) { + REQUIRE_PROMISE(stdio); if (!validate_write_typed(ts)) return -EFAULT; @@ -3832,6 +3999,7 @@ int Process::sys$clock_gettime(clockid_t clock_id, timespec* ts) int Process::sys$clock_nanosleep(const Syscall::SC_clock_nanosleep_params* user_params) { + REQUIRE_PROMISE(stdio); if (!validate_read_typed(user_params)) return -EFAULT; Syscall::SC_clock_nanosleep_params params; @@ -3881,6 +4049,7 @@ int Process::sys$clock_nanosleep(const Syscall::SC_clock_nanosleep_params* user_ int Process::sys$sync() { + REQUIRE_PROMISE(stdio); VFS::the().sync(); return 0; } @@ -3906,6 +4075,8 @@ int Process::sys$module_load(const char* user_path, size_t path_length) if (!is_superuser()) return -EPERM; + REQUIRE_NO_PROMISES; + auto path = get_syscall_path_argument(user_path, path_length); if (path.is_error()) return path.error(); @@ -4024,6 +4195,8 @@ int Process::sys$module_unload(const char* user_name, size_t name_length) if (!is_superuser()) return -EPERM; + REQUIRE_NO_PROMISES; + auto module_name = validate_and_copy_string_from_user(user_name, name_length); if (module_name.is_null()) return -EFAULT; @@ -4041,6 +4214,7 @@ int Process::sys$module_unload(const char* user_name, size_t name_length) int Process::sys$profiling_enable(pid_t pid) { + REQUIRE_NO_PROMISES; InterruptDisabler disabler; auto* process = Process::from_pid(pid); if (!process) @@ -4140,6 +4314,7 @@ int Process::sys$futex(const Syscall::SC_futex_params* user_params) int Process::sys$set_thread_boost(int tid, int amount) { + REQUIRE_PROMISE(proc); if (amount < 0 || amount > 20) return -EINVAL; InterruptDisabler disabler; @@ -4156,6 +4331,7 @@ int Process::sys$set_thread_boost(int tid, int amount) int Process::sys$set_process_boost(pid_t pid, int amount) { + REQUIRE_PROMISE(proc); if (amount < 0 || amount > 20) return -EINVAL; InterruptDisabler disabler; @@ -4172,6 +4348,7 @@ int Process::sys$chroot(const char* user_path, size_t path_length) { if (!is_superuser()) return -EPERM; + REQUIRE_PROMISE(chroot); auto path = get_syscall_path_argument(user_path, path_length); if (path.is_error()) return path.error(); @@ -4202,3 +4379,68 @@ void Process::set_root_directory(const Custody& root) { m_root_directory = root; } + +int Process::sys$pledge(const Syscall::SC_pledge_params* user_params) +{ + if (!validate_read_typed(user_params)) + return -EFAULT; + Syscall::SC_pledge_params params; + copy_from_user(¶ms, user_params); + + if (params.promises.length > 1024 || params.execpromises.length > 1024) + return -E2BIG; + + String promises; + if (params.promises.characters) { + promises = validate_and_copy_string_from_user(params.promises); + if (promises.is_null()) + return -EFAULT; + } + + String execpromises; + if (params.execpromises.characters) { + execpromises = validate_and_copy_string_from_user(params.execpromises); + if (execpromises.is_null()) + return -EFAULT; + } + + auto parse_pledge = [&](auto& pledge_spec, u32& mask) { + auto parts = pledge_spec.split_view(' '); + for (auto& part : parts) { +#define __ENUMERATE_PLEDGE_PROMISE(x) \ + if (part == #x) { \ + mask |= (1u << (u32)Pledge::x); \ + continue; \ + } + ENUMERATE_PLEDGE_PROMISES +#undef __ENUMERATE_PLEDGE_PROMISE + if (part == "dns") { + // "dns" is an alias for "unix" since DNS queries go via LookupServer + mask |= (1u << (u32)Pledge::unix); + continue; + } + return false; + } + return true; + }; + + if (!promises.is_null()) { + u32 new_promises = 0; + if (!parse_pledge(promises, new_promises)) + return -EINVAL; + if (m_promises && new_promises & ~m_promises) + return -EPERM; + m_promises = new_promises; + } + + if (!execpromises.is_null()) { + u32 new_execpromises = 0; + if (!parse_pledge(execpromises, new_execpromises)) + return -EINVAL; + if (m_execpromises && new_execpromises & ~m_execpromises) + return -EPERM; + m_execpromises = new_execpromises; + } + + return 0; +} diff --git a/Kernel/Process.h b/Kernel/Process.h index c4491f26a0..c096e27873 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -30,6 +30,30 @@ void kgettimeofday(timeval&); extern VirtualAddress g_return_to_ring3_from_signal_trampoline; +#define ENUMERATE_PLEDGE_PROMISES \ + __ENUMERATE_PLEDGE_PROMISE(stdio) \ + __ENUMERATE_PLEDGE_PROMISE(rpath) \ + __ENUMERATE_PLEDGE_PROMISE(wpath) \ + __ENUMERATE_PLEDGE_PROMISE(cpath) \ + __ENUMERATE_PLEDGE_PROMISE(dpath) \ + __ENUMERATE_PLEDGE_PROMISE(inet) \ + __ENUMERATE_PLEDGE_PROMISE(id) \ + __ENUMERATE_PLEDGE_PROMISE(proc) \ + __ENUMERATE_PLEDGE_PROMISE(exec) \ + __ENUMERATE_PLEDGE_PROMISE(unix) \ + __ENUMERATE_PLEDGE_PROMISE(fattr) \ + __ENUMERATE_PLEDGE_PROMISE(tty) \ + __ENUMERATE_PLEDGE_PROMISE(chown) \ + __ENUMERATE_PLEDGE_PROMISE(chroot) \ + __ENUMERATE_PLEDGE_PROMISE(thread) \ + __ENUMERATE_PLEDGE_PROMISE(shared_buffer) + +enum class Pledge : u32 { +#define __ENUMERATE_PLEDGE_PROMISE(x) x, + ENUMERATE_PLEDGE_PROMISES +#undef __ENUMERATE_PLEDGE_PROMISE +}; + class Process : public InlineLinkedListNode<Process> , public Weakable<Process> { friend class InlineLinkedListNode<Process>; @@ -230,6 +254,7 @@ public: int sys$set_thread_boost(int tid, int amount); int sys$set_process_boost(pid_t, int amount); int sys$chroot(const char* path, size_t path_length); + int sys$pledge(const Syscall::SC_pledge_params*); static void initialize(); @@ -316,6 +341,9 @@ public: Custody& root_directory_for_procfs(); void set_root_directory(const Custody&); + bool has_promises() const { return m_promises; } + bool has_promised(Pledge pledge) const { return m_promises & (1u << (u32)pledge); } + private: friend class MemoryManager; friend class Scheduler; @@ -407,6 +435,9 @@ private: u32 m_priority_boost { 0 }; + u32 m_promises { 0 }; + u32 m_execpromises { 0 }; + WaitQueue& futex_queue(i32*); HashMap<u32, OwnPtr<WaitQueue>> m_futex_queues; }; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 70d056f993..6a65ed564e 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -148,7 +148,8 @@ typedef u32 socklen_t; __ENUMERATE_SYSCALL(futex) \ __ENUMERATE_SYSCALL(set_thread_boost) \ __ENUMERATE_SYSCALL(set_process_boost) \ - __ENUMERATE_SYSCALL(chroot) + __ENUMERATE_SYSCALL(chroot) \ + __ENUMERATE_SYSCALL(pledge) namespace Syscall { @@ -360,6 +361,11 @@ struct SC_mount_params { int flags; }; +struct SC_pledge_params { + StringArgument promises; + StringArgument execpromises; +}; + void initialize(); int sync(); diff --git a/Userland/ping.cpp b/Userland/ping.cpp index 7318cb82ec..8464740c5d 100644 --- a/Userland/ping.cpp +++ b/Userland/ping.cpp @@ -26,6 +26,11 @@ uint16_t internet_checksum(const void* ptr, size_t count) int main(int argc, char** argv) { + if (pledge("stdio id inet dns", nullptr) < 0) { + perror("pledge"); + return 1; + } + if (argc != 2) { printf("usage: ping <host>\n"); return 0; @@ -42,6 +47,11 @@ int main(int argc, char** argv) return 1; } + if (pledge("stdio inet dns", nullptr) < 0) { + perror("pledge"); + return 1; + } + struct timeval timeout { 1, 0 }; @@ -57,6 +67,11 @@ int main(int argc, char** argv) return 1; } + if (pledge("stdio inet", nullptr) < 0) { + perror("pledge"); + return 1; + } + pid_t pid = getpid(); sockaddr_in peer_address; |