1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:18:11 +00:00

Kernel: Make all syscall functions return KResultOr<T>

This makes it a lot easier to return errors since we no longer have to
worry about negating EFOO errors and can just return them flat.
This commit is contained in:
Andreas Kling 2021-03-01 13:49:16 +01:00
parent 9af1e1a3bf
commit ac71775de5
70 changed files with 747 additions and 742 deletions

View file

@ -212,151 +212,151 @@ public:
void stop_tracing(); void stop_tracing();
void tracer_trap(Thread&, const RegisterState&); void tracer_trap(Thread&, const RegisterState&);
int sys$yield(); KResultOr<int> sys$yield();
int sys$sync(); KResultOr<int> sys$sync();
int sys$beep(); KResultOr<int> sys$beep();
int sys$get_process_name(Userspace<char*> buffer, size_t buffer_size); KResultOr<int> sys$get_process_name(Userspace<char*> buffer, size_t buffer_size);
int sys$set_process_name(Userspace<const char*> user_name, size_t user_name_length); KResultOr<int> sys$set_process_name(Userspace<const char*> user_name, size_t user_name_length);
int sys$watch_file(Userspace<const char*> path, size_t path_length); KResultOr<int> sys$watch_file(Userspace<const char*> path, size_t path_length);
int sys$dbgputch(u8); KResultOr<int> sys$dbgputch(u8);
int sys$dbgputstr(Userspace<const u8*>, int length); KResultOr<int> sys$dbgputstr(Userspace<const u8*>, int length);
int sys$dump_backtrace(); KResultOr<int> sys$dump_backtrace();
pid_t sys$gettid(); KResultOr<pid_t> sys$gettid();
int sys$donate(pid_t tid); KResultOr<int> sys$donate(pid_t tid);
int sys$ftruncate(int fd, off_t); KResultOr<int> sys$ftruncate(int fd, off_t);
pid_t sys$setsid(); KResultOr<pid_t> sys$setsid();
pid_t sys$getsid(pid_t); KResultOr<pid_t> sys$getsid(pid_t);
int sys$setpgid(pid_t pid, pid_t pgid); KResultOr<int> sys$setpgid(pid_t pid, pid_t pgid);
pid_t sys$getpgrp(); KResultOr<pid_t> sys$getpgrp();
pid_t sys$getpgid(pid_t); KResultOr<pid_t> sys$getpgid(pid_t);
uid_t sys$getuid(); KResultOr<uid_t> sys$getuid();
gid_t sys$getgid(); KResultOr<gid_t> sys$getgid();
uid_t sys$geteuid(); KResultOr<uid_t> sys$geteuid();
gid_t sys$getegid(); KResultOr<gid_t> sys$getegid();
pid_t sys$getpid(); KResultOr<pid_t> sys$getpid();
pid_t sys$getppid(); KResultOr<pid_t> sys$getppid();
int sys$getresuid(Userspace<uid_t*>, Userspace<uid_t*>, Userspace<uid_t*>); KResultOr<int> sys$getresuid(Userspace<uid_t*>, Userspace<uid_t*>, Userspace<uid_t*>);
int sys$getresgid(Userspace<gid_t*>, Userspace<gid_t*>, Userspace<gid_t*>); KResultOr<int> sys$getresgid(Userspace<gid_t*>, Userspace<gid_t*>, Userspace<gid_t*>);
mode_t sys$umask(mode_t); KResultOr<mode_t> sys$umask(mode_t);
int sys$open(Userspace<const Syscall::SC_open_params*>); KResultOr<int> sys$open(Userspace<const Syscall::SC_open_params*>);
int sys$close(int fd); KResultOr<int> sys$close(int fd);
ssize_t sys$read(int fd, Userspace<u8*>, ssize_t); KResultOr<ssize_t> sys$read(int fd, Userspace<u8*>, ssize_t);
ssize_t sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count); KResultOr<ssize_t> sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count);
ssize_t sys$write(int fd, const u8*, ssize_t); KResultOr<ssize_t> sys$write(int fd, const u8*, ssize_t);
ssize_t sys$writev(int fd, Userspace<const struct iovec*> iov, int iov_count); KResultOr<ssize_t> sys$writev(int fd, Userspace<const struct iovec*> iov, int iov_count);
int sys$fstat(int fd, Userspace<stat*>); KResultOr<int> sys$fstat(int fd, Userspace<stat*>);
int sys$stat(Userspace<const Syscall::SC_stat_params*>); KResultOr<int> sys$stat(Userspace<const Syscall::SC_stat_params*>);
int sys$lseek(int fd, off_t, int whence); KResultOr<int> sys$lseek(int fd, off_t, int whence);
int sys$kill(pid_t pid_or_pgid, int sig); KResultOr<int> sys$kill(pid_t pid_or_pgid, int sig);
[[noreturn]] void sys$exit(int status); [[noreturn]] void sys$exit(int status);
int sys$sigreturn(RegisterState& registers); KResultOr<int> sys$sigreturn(RegisterState& registers);
pid_t sys$waitid(Userspace<const Syscall::SC_waitid_params*>); KResultOr<pid_t> sys$waitid(Userspace<const Syscall::SC_waitid_params*>);
FlatPtr sys$mmap(Userspace<const Syscall::SC_mmap_params*>); KResultOr<FlatPtr> sys$mmap(Userspace<const Syscall::SC_mmap_params*>);
FlatPtr sys$mremap(Userspace<const Syscall::SC_mremap_params*>); KResultOr<FlatPtr> sys$mremap(Userspace<const Syscall::SC_mremap_params*>);
int sys$munmap(void*, size_t size); KResultOr<int> sys$munmap(void*, size_t size);
int sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*>); KResultOr<int> sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*>);
int sys$mprotect(void*, size_t, int prot); KResultOr<int> sys$mprotect(void*, size_t, int prot);
int sys$madvise(void*, size_t, int advice); KResultOr<int> sys$madvise(void*, size_t, int advice);
int sys$msyscall(void*); KResultOr<int> sys$msyscall(void*);
int sys$purge(int mode); KResultOr<int> sys$purge(int mode);
int sys$select(const Syscall::SC_select_params*); KResultOr<int> sys$select(const Syscall::SC_select_params*);
int sys$poll(Userspace<const Syscall::SC_poll_params*>); KResultOr<int> sys$poll(Userspace<const Syscall::SC_poll_params*>);
ssize_t sys$get_dir_entries(int fd, void*, ssize_t); KResultOr<ssize_t> sys$get_dir_entries(int fd, void*, ssize_t);
int sys$getcwd(Userspace<char*>, size_t); KResultOr<int> sys$getcwd(Userspace<char*>, size_t);
int sys$chdir(Userspace<const char*>, size_t); KResultOr<int> sys$chdir(Userspace<const char*>, size_t);
int sys$fchdir(int fd); KResultOr<int> sys$fchdir(int fd);
int sys$adjtime(Userspace<const timeval*>, Userspace<timeval*>); KResultOr<int> sys$adjtime(Userspace<const timeval*>, Userspace<timeval*>);
int sys$gettimeofday(Userspace<timeval*>); KResultOr<int> sys$gettimeofday(Userspace<timeval*>);
int sys$clock_gettime(clockid_t, Userspace<timespec*>); KResultOr<int> sys$clock_gettime(clockid_t, Userspace<timespec*>);
int sys$clock_settime(clockid_t, Userspace<const timespec*>); KResultOr<int> sys$clock_settime(clockid_t, Userspace<const timespec*>);
int sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_params*>); KResultOr<int> sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_params*>);
int sys$gethostname(Userspace<char*>, ssize_t); KResultOr<int> sys$gethostname(Userspace<char*>, ssize_t);
int sys$sethostname(Userspace<const char*>, ssize_t); KResultOr<int> sys$sethostname(Userspace<const char*>, ssize_t);
int sys$uname(Userspace<utsname*>); KResultOr<int> sys$uname(Userspace<utsname*>);
int sys$readlink(Userspace<const Syscall::SC_readlink_params*>); KResultOr<int> sys$readlink(Userspace<const Syscall::SC_readlink_params*>);
int sys$ttyname(int fd, Userspace<char*>, size_t); KResultOr<int> sys$ttyname(int fd, Userspace<char*>, size_t);
int sys$ptsname(int fd, Userspace<char*>, size_t); KResultOr<int> sys$ptsname(int fd, Userspace<char*>, size_t);
pid_t sys$fork(RegisterState&); KResultOr<pid_t> sys$fork(RegisterState&);
int sys$execve(Userspace<const Syscall::SC_execve_params*>); KResultOr<int> sys$execve(Userspace<const Syscall::SC_execve_params*>);
int sys$dup2(int old_fd, int new_fd); KResultOr<int> sys$dup2(int old_fd, int new_fd);
int sys$sigaction(int signum, const sigaction* act, sigaction* old_act); KResultOr<int> sys$sigaction(int signum, const sigaction* act, sigaction* old_act);
int sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<sigset_t*> old_set); KResultOr<int> sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<sigset_t*> old_set);
int sys$sigpending(Userspace<sigset_t*>); KResultOr<int> sys$sigpending(Userspace<sigset_t*>);
int sys$getgroups(ssize_t, Userspace<gid_t*>); KResultOr<int> sys$getgroups(ssize_t, Userspace<gid_t*>);
int sys$setgroups(ssize_t, Userspace<const gid_t*>); KResultOr<int> sys$setgroups(ssize_t, Userspace<const gid_t*>);
int sys$pipe(int pipefd[2], int flags); KResultOr<int> sys$pipe(int pipefd[2], int flags);
int sys$killpg(pid_t pgrp, int sig); KResultOr<int> sys$killpg(pid_t pgrp, int sig);
int sys$seteuid(uid_t); KResultOr<int> sys$seteuid(uid_t);
int sys$setegid(gid_t); KResultOr<int> sys$setegid(gid_t);
int sys$setuid(uid_t); KResultOr<int> sys$setuid(uid_t);
int sys$setgid(gid_t); KResultOr<int> sys$setgid(gid_t);
int sys$setresuid(uid_t, uid_t, uid_t); KResultOr<int> sys$setresuid(uid_t, uid_t, uid_t);
int sys$setresgid(gid_t, gid_t, gid_t); KResultOr<int> sys$setresgid(gid_t, gid_t, gid_t);
unsigned sys$alarm(unsigned seconds); KResultOr<unsigned> sys$alarm(unsigned seconds);
int sys$access(Userspace<const char*> pathname, size_t path_length, int mode); KResultOr<int> sys$access(Userspace<const char*> pathname, size_t path_length, int mode);
int sys$fcntl(int fd, int cmd, u32 extra_arg); KResultOr<int> sys$fcntl(int fd, int cmd, u32 extra_arg);
int sys$ioctl(int fd, unsigned request, FlatPtr arg); KResultOr<int> sys$ioctl(int fd, unsigned request, FlatPtr arg);
int sys$mkdir(Userspace<const char*> pathname, size_t path_length, mode_t mode); KResultOr<int> sys$mkdir(Userspace<const char*> pathname, size_t path_length, mode_t mode);
clock_t sys$times(Userspace<tms*>); KResultOr<clock_t> sys$times(Userspace<tms*>);
int sys$utime(Userspace<const char*> pathname, size_t path_length, Userspace<const struct utimbuf*>); KResultOr<int> sys$utime(Userspace<const char*> pathname, size_t path_length, Userspace<const struct utimbuf*>);
int sys$link(Userspace<const Syscall::SC_link_params*>); KResultOr<int> sys$link(Userspace<const Syscall::SC_link_params*>);
int sys$unlink(Userspace<const char*> pathname, size_t path_length); KResultOr<int> sys$unlink(Userspace<const char*> pathname, size_t path_length);
int sys$symlink(Userspace<const Syscall::SC_symlink_params*>); KResultOr<int> sys$symlink(Userspace<const Syscall::SC_symlink_params*>);
int sys$rmdir(Userspace<const char*> pathname, size_t path_length); KResultOr<int> sys$rmdir(Userspace<const char*> pathname, size_t path_length);
int sys$mount(Userspace<const Syscall::SC_mount_params*>); KResultOr<int> sys$mount(Userspace<const Syscall::SC_mount_params*>);
int sys$umount(Userspace<const char*> mountpoint, size_t mountpoint_length); KResultOr<int> sys$umount(Userspace<const char*> mountpoint, size_t mountpoint_length);
int sys$chmod(Userspace<const char*> pathname, size_t path_length, mode_t); KResultOr<int> sys$chmod(Userspace<const char*> pathname, size_t path_length, mode_t);
int sys$fchmod(int fd, mode_t); KResultOr<int> sys$fchmod(int fd, mode_t);
int sys$chown(Userspace<const Syscall::SC_chown_params*>); KResultOr<int> sys$chown(Userspace<const Syscall::SC_chown_params*>);
int sys$fchown(int fd, uid_t, gid_t); KResultOr<int> sys$fchown(int fd, uid_t, gid_t);
int sys$socket(int domain, int type, int protocol); KResultOr<int> sys$socket(int domain, int type, int protocol);
int sys$bind(int sockfd, Userspace<const sockaddr*> addr, socklen_t); KResultOr<int> sys$bind(int sockfd, Userspace<const sockaddr*> addr, socklen_t);
int sys$listen(int sockfd, int backlog); KResultOr<int> sys$listen(int sockfd, int backlog);
int sys$accept(int sockfd, Userspace<sockaddr*>, Userspace<socklen_t*>); KResultOr<int> sys$accept(int sockfd, Userspace<sockaddr*>, Userspace<socklen_t*>);
int sys$connect(int sockfd, Userspace<const sockaddr*>, socklen_t); KResultOr<int> sys$connect(int sockfd, Userspace<const sockaddr*>, socklen_t);
int sys$shutdown(int sockfd, int how); KResultOr<int> sys$shutdown(int sockfd, int how);
ssize_t sys$sendmsg(int sockfd, Userspace<const struct msghdr*>, int flags); KResultOr<ssize_t> sys$sendmsg(int sockfd, Userspace<const struct msghdr*>, int flags);
ssize_t sys$recvmsg(int sockfd, Userspace<struct msghdr*>, int flags); KResultOr<ssize_t> sys$recvmsg(int sockfd, Userspace<struct msghdr*>, int flags);
int sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*>); KResultOr<int> sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*>);
int sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*>); KResultOr<int> sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*>);
int sys$getsockname(Userspace<const Syscall::SC_getsockname_params*>); KResultOr<int> sys$getsockname(Userspace<const Syscall::SC_getsockname_params*>);
int sys$getpeername(Userspace<const Syscall::SC_getpeername_params*>); KResultOr<int> sys$getpeername(Userspace<const Syscall::SC_getpeername_params*>);
int sys$sched_setparam(pid_t pid, Userspace<const struct sched_param*>); KResultOr<int> sys$sched_setparam(pid_t pid, Userspace<const struct sched_param*>);
int sys$sched_getparam(pid_t pid, Userspace<struct sched_param*>); KResultOr<int> sys$sched_getparam(pid_t pid, Userspace<struct sched_param*>);
int sys$create_thread(void* (*)(void*), Userspace<const Syscall::SC_create_thread_params*>); KResultOr<int> sys$create_thread(void* (*)(void*), Userspace<const Syscall::SC_create_thread_params*>);
void sys$exit_thread(Userspace<void*>); [[noreturn]] void sys$exit_thread(Userspace<void*>);
int sys$join_thread(pid_t tid, Userspace<void**> exit_value); KResultOr<int> sys$join_thread(pid_t tid, Userspace<void**> exit_value);
int sys$detach_thread(pid_t tid); KResultOr<int> sys$detach_thread(pid_t tid);
int sys$set_thread_name(pid_t tid, Userspace<const char*> buffer, size_t buffer_size); KResultOr<int> sys$set_thread_name(pid_t tid, Userspace<const char*> buffer, size_t buffer_size);
int sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buffer_size); KResultOr<int> sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buffer_size);
int sys$rename(Userspace<const Syscall::SC_rename_params*>); KResultOr<int> sys$rename(Userspace<const Syscall::SC_rename_params*>);
int sys$mknod(Userspace<const Syscall::SC_mknod_params*>); KResultOr<int> sys$mknod(Userspace<const Syscall::SC_mknod_params*>);
int sys$halt(); KResultOr<int> sys$halt();
int sys$reboot(); KResultOr<int> sys$reboot();
int sys$realpath(Userspace<const Syscall::SC_realpath_params*>); KResultOr<int> sys$realpath(Userspace<const Syscall::SC_realpath_params*>);
ssize_t sys$getrandom(Userspace<void*>, size_t, unsigned int); KResultOr<ssize_t> sys$getrandom(Userspace<void*>, size_t, unsigned int);
int sys$getkeymap(Userspace<const Syscall::SC_getkeymap_params*>); KResultOr<int> sys$getkeymap(Userspace<const Syscall::SC_getkeymap_params*>);
int sys$setkeymap(Userspace<const Syscall::SC_setkeymap_params*>); KResultOr<int> sys$setkeymap(Userspace<const Syscall::SC_setkeymap_params*>);
int sys$module_load(Userspace<const char*> path, size_t path_length); KResultOr<int> sys$module_load(Userspace<const char*> path, size_t path_length);
int sys$module_unload(Userspace<const char*> name, size_t name_length); KResultOr<int> sys$module_unload(Userspace<const char*> name, size_t name_length);
int sys$profiling_enable(pid_t); KResultOr<int> sys$profiling_enable(pid_t);
int sys$profiling_disable(pid_t); KResultOr<int> sys$profiling_disable(pid_t);
int sys$futex(Userspace<const Syscall::SC_futex_params*>); KResultOr<int> sys$futex(Userspace<const Syscall::SC_futex_params*>);
int sys$chroot(Userspace<const char*> path, size_t path_length, int mount_flags); KResultOr<int> sys$chroot(Userspace<const char*> path, size_t path_length, int mount_flags);
int sys$pledge(Userspace<const Syscall::SC_pledge_params*>); KResultOr<int> sys$pledge(Userspace<const Syscall::SC_pledge_params*>);
int sys$unveil(Userspace<const Syscall::SC_unveil_params*>); KResultOr<int> sys$unveil(Userspace<const Syscall::SC_unveil_params*>);
int sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2); KResultOr<int> sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2);
int sys$get_stack_bounds(FlatPtr* stack_base, size_t* stack_size); KResultOr<int> sys$get_stack_bounds(FlatPtr* stack_base, size_t* stack_size);
int sys$ptrace(Userspace<const Syscall::SC_ptrace_params*>); KResultOr<int> sys$ptrace(Userspace<const Syscall::SC_ptrace_params*>);
int sys$sendfd(int sockfd, int fd); KResultOr<int> sys$sendfd(int sockfd, int fd);
int sys$recvfd(int sockfd, int options); KResultOr<int> sys$recvfd(int sockfd, int options);
long sys$sysconf(int name); KResultOr<long> sys$sysconf(int name);
int sys$disown(ProcessID); KResultOr<int> sys$disown(ProcessID);
FlatPtr sys$allocate_tls(size_t); KResultOr<FlatPtr> sys$allocate_tls(size_t);
int sys$prctl(int option, FlatPtr arg1, FlatPtr arg2); KResultOr<int> sys$prctl(int option, FlatPtr arg1, FlatPtr arg2);
int sys$set_coredump_metadata(Userspace<const Syscall::SC_set_coredump_metadata_params*>); KResultOr<int> sys$set_coredump_metadata(Userspace<const Syscall::SC_set_coredump_metadata_params*>);
void sys$abort(); [[noreturn]] void sys$abort();
int sys$anon_create(size_t, int options); KResultOr<int> sys$anon_create(size_t, int options);
template<bool sockname, typename Params> template<bool sockname, typename Params>
int get_sock_or_peer_name(const Params&); int get_sock_or_peer_name(const Params&);
@ -479,7 +479,7 @@ private:
bool dump_perfcore(); bool dump_perfcore();
KResult do_exec(NonnullRefPtr<FileDescription> main_program_description, Vector<String> arguments, Vector<String> environment, RefPtr<FileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags, const Elf32_Ehdr& main_program_header); KResult do_exec(NonnullRefPtr<FileDescription> main_program_description, Vector<String> arguments, Vector<String> environment, RefPtr<FileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags, const Elf32_Ehdr& main_program_header);
ssize_t do_write(FileDescription&, const UserOrKernelBuffer&, size_t); KResultOr<ssize_t> do_write(FileDescription&, const UserOrKernelBuffer&, size_t);
KResultOr<RefPtr<FileDescription>> find_elf_interpreter_for_executable(const String& path, const Elf32_Ehdr& elf_header, int nread, size_t file_size); KResultOr<RefPtr<FileDescription>> find_elf_interpreter_for_executable(const String& path, const Elf32_Ehdr& elf_header, int nread, size_t file_size);

View file

@ -69,7 +69,7 @@ asm(
namespace Syscall { namespace Syscall {
static int handle(RegisterState&, u32 function, u32 arg1, u32 arg2, u32 arg3); static KResultOr<FlatPtr> handle(RegisterState&, FlatPtr function, FlatPtr arg1, FlatPtr arg2, FlatPtr arg3);
UNMAP_AFTER_INIT void initialize() UNMAP_AFTER_INIT void initialize()
{ {
@ -78,14 +78,15 @@ UNMAP_AFTER_INIT void initialize()
} }
#pragma GCC diagnostic ignored "-Wcast-function-type" #pragma GCC diagnostic ignored "-Wcast-function-type"
typedef int (Process::*Handler)(u32, u32, u32); typedef KResultOr<FlatPtr> (Process::*Handler)(FlatPtr, FlatPtr, FlatPtr);
typedef KResultOr<FlatPtr> (Process::*HandlerWithRegisterState)(RegisterState&);
#define __ENUMERATE_SYSCALL(x) reinterpret_cast<Handler>(&Process::sys$##x), #define __ENUMERATE_SYSCALL(x) reinterpret_cast<Handler>(&Process::sys$##x),
static Handler s_syscall_table[] = { static Handler s_syscall_table[] = {
ENUMERATE_SYSCALLS(__ENUMERATE_SYSCALL) ENUMERATE_SYSCALLS(__ENUMERATE_SYSCALL)
}; };
#undef __ENUMERATE_SYSCALL #undef __ENUMERATE_SYSCALL
int handle(RegisterState& regs, u32 function, u32 arg1, u32 arg2, u32 arg3) KResultOr<FlatPtr> handle(RegisterState& regs, FlatPtr function, FlatPtr arg1, FlatPtr arg2, FlatPtr arg3)
{ {
VERIFY_INTERRUPTS_ENABLED(); VERIFY_INTERRUPTS_ENABLED();
auto current_thread = Thread::current(); auto current_thread = Thread::current();
@ -102,18 +103,17 @@ int handle(RegisterState& regs, u32 function, u32 arg1, u32 arg2, u32 arg3)
} }
if (function == SC_exit) if (function == SC_exit)
process.sys$exit((int)arg1); process.sys$exit(arg1);
else else
process.sys$exit_thread(arg1); process.sys$exit_thread(arg1);
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
return 0;
} }
if (function == SC_fork) if (function == SC_fork || function == SC_sigreturn) {
return process.sys$fork(regs); // These syscalls want the RegisterState& rather than individual parameters.
auto handler = (HandlerWithRegisterState)s_syscall_table[function];
if (function == SC_sigreturn) return (process.*(handler))(regs);
return process.sys$sigreturn(regs); }
if (function >= Function::__Count) { if (function >= Function::__Count) {
dbgln("Unknown syscall {} requested ({:08x}, {:08x}, {:08x})", function, arg1, arg2, arg3); dbgln("Unknown syscall {} requested ({:08x}, {:08x}, {:08x})", function, arg1, arg2, arg3);
@ -162,7 +162,7 @@ void syscall_handler(TrapFrame* trap)
asm volatile("" asm volatile(""
: "=m"(*ptr)); : "=m"(*ptr));
static constexpr u32 iopl_mask = 3u << 12; static constexpr FlatPtr iopl_mask = 3u << 12;
if ((regs.eflags & (iopl_mask)) != 0) { if ((regs.eflags & (iopl_mask)) != 0) {
PANIC("Syscall from process with IOPL != 0"); PANIC("Syscall from process with IOPL != 0");
@ -192,11 +192,16 @@ void syscall_handler(TrapFrame* trap)
handle_crash(regs, "Syscall from non-syscall region", SIGSEGV); handle_crash(regs, "Syscall from non-syscall region", SIGSEGV);
} }
u32 function = regs.eax; auto function = regs.eax;
u32 arg1 = regs.edx; auto arg1 = regs.edx;
u32 arg2 = regs.ecx; auto arg2 = regs.ecx;
u32 arg3 = regs.ebx; auto arg3 = regs.ebx;
regs.eax = Syscall::handle(regs, function, arg1, arg2, arg3);
auto result = Syscall::handle(regs, function, arg1, arg2, arg3);
if (result.is_error())
regs.eax = result.error();
else
regs.eax = result.value();
process.big_lock().unlock(); process.big_lock().unlock();

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$access(Userspace<const char*> user_path, size_t path_length, int mode) KResultOr<int> Process::sys$access(Userspace<const char*> user_path, size_t path_length, int mode)
{ {
REQUIRE_PROMISE(rpath); REQUIRE_PROMISE(rpath);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);

View file

@ -29,7 +29,7 @@
namespace Kernel { namespace Kernel {
unsigned Process::sys$alarm(unsigned seconds) KResultOr<unsigned> Process::sys$alarm(unsigned seconds)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
unsigned previous_alarm_remaining = 0; unsigned previous_alarm_remaining = 0;

View file

@ -31,15 +31,15 @@
namespace Kernel { namespace Kernel {
int Process::sys$anon_create(size_t size, int options) KResultOr<int> Process::sys$anon_create(size_t size, int options)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (!size) if (!size)
return -EINVAL; return EINVAL;
if (size % PAGE_SIZE) if (size % PAGE_SIZE)
return -EINVAL; return EINVAL;
int new_fd = alloc_fd(); int new_fd = alloc_fd();
if (new_fd < 0) if (new_fd < 0)
@ -47,7 +47,7 @@ int Process::sys$anon_create(size_t size, int options)
auto vmobject = AnonymousVMObject::create_with_size(size, AllocationStrategy::Reserve); auto vmobject = AnonymousVMObject::create_with_size(size, AllocationStrategy::Reserve);
if (!vmobject) if (!vmobject)
return -ENOMEM; return ENOMEM;
auto anon_file = AnonymousFile::create(vmobject.release_nonnull()); auto anon_file = AnonymousFile::create(vmobject.release_nonnull());
auto description_or_error = FileDescription::create(*anon_file); auto description_or_error = FileDescription::create(*anon_file);

View file

@ -29,13 +29,13 @@
namespace Kernel { namespace Kernel {
int Process::sys$beep() KResultOr<int> Process::sys$beep()
{ {
PCSpeaker::tone_on(440); PCSpeaker::tone_on(440);
auto result = Thread::current()->sleep({ 0, 200 }); auto result = Thread::current()->sleep({ 0, 200 });
PCSpeaker::tone_off(); PCSpeaker::tone_off();
if (result.was_interrupted()) if (result.was_interrupted())
return -EINTR; return EINTR;
return 0; return 0;
} }

View file

@ -31,7 +31,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$chdir(Userspace<const char*> user_path, size_t path_length) KResultOr<int> Process::sys$chdir(Userspace<const char*> user_path, size_t path_length)
{ {
REQUIRE_PROMISE(rpath); REQUIRE_PROMISE(rpath);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);
@ -44,24 +44,24 @@ int Process::sys$chdir(Userspace<const char*> user_path, size_t path_length)
return 0; return 0;
} }
int Process::sys$fchdir(int fd) KResultOr<int> Process::sys$fchdir(int fd)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_directory()) if (!description->is_directory())
return -ENOTDIR; return ENOTDIR;
if (!description->metadata().may_execute(*this)) if (!description->metadata().may_execute(*this))
return -EACCES; return EACCES;
m_cwd = description->custody(); m_cwd = description->custody();
return 0; return 0;
} }
int Process::sys$getcwd(Userspace<char*> buffer, size_t size) KResultOr<int> Process::sys$getcwd(Userspace<char*> buffer, size_t size)
{ {
REQUIRE_PROMISE(rpath); REQUIRE_PROMISE(rpath);
@ -70,7 +70,7 @@ int Process::sys$getcwd(Userspace<char*> buffer, size_t size)
size_t ideal_size = path.length() + 1; size_t ideal_size = path.length() + 1;
auto size_to_copy = min(ideal_size, size); auto size_to_copy = min(ideal_size, size);
if (!copy_to_user(buffer, path.characters(), size_to_copy)) if (!copy_to_user(buffer, path.characters(), size_to_copy))
return -EFAULT; return EFAULT;
// Note: we return the whole size here, not the copied size. // Note: we return the whole size here, not the copied size.
return ideal_size; return ideal_size;
} }

View file

@ -31,7 +31,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$chmod(Userspace<const char*> user_path, size_t path_length, mode_t mode) KResultOr<int> Process::sys$chmod(Userspace<const char*> user_path, size_t path_length, mode_t mode)
{ {
REQUIRE_PROMISE(fattr); REQUIRE_PROMISE(fattr);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);
@ -40,12 +40,12 @@ int Process::sys$chmod(Userspace<const char*> user_path, size_t path_length, mod
return VFS::the().chmod(path.value(), mode, current_directory()); return VFS::the().chmod(path.value(), mode, current_directory());
} }
int Process::sys$fchmod(int fd, mode_t mode) KResultOr<int> Process::sys$fchmod(int fd, mode_t mode)
{ {
REQUIRE_PROMISE(fattr); REQUIRE_PROMISE(fattr);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
return description->chmod(mode); return description->chmod(mode);
} }

View file

@ -29,21 +29,21 @@
namespace Kernel { namespace Kernel {
int Process::sys$fchown(int fd, uid_t uid, gid_t gid) KResultOr<int> Process::sys$fchown(int fd, uid_t uid, gid_t gid)
{ {
REQUIRE_PROMISE(chown); REQUIRE_PROMISE(chown);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
return description->chown(uid, gid); return description->chown(uid, gid);
} }
int Process::sys$chown(Userspace<const Syscall::SC_chown_params*> user_params) KResultOr<int> Process::sys$chown(Userspace<const Syscall::SC_chown_params*> user_params)
{ {
REQUIRE_PROMISE(chown); REQUIRE_PROMISE(chown);
Syscall::SC_chown_params params; Syscall::SC_chown_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto path = get_syscall_path_argument(params.path); auto path = get_syscall_path_argument(params.path);
if (path.is_error()) if (path.is_error())
return path.error(); return path.error();

View file

@ -31,10 +31,10 @@
namespace Kernel { namespace Kernel {
int Process::sys$chroot(Userspace<const char*> user_path, size_t path_length, int mount_flags) KResultOr<int> Process::sys$chroot(Userspace<const char*> user_path, size_t path_length, int mount_flags)
{ {
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
REQUIRE_PROMISE(chroot); REQUIRE_PROMISE(chroot);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);
if (path.is_error()) if (path.is_error())

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts) KResultOr<int> Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
@ -39,42 +39,42 @@ int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
return ts.error(); return ts.error();
if (!copy_to_user(user_ts, &ts.value())) if (!copy_to_user(user_ts, &ts.value()))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$clock_settime(clockid_t clock_id, Userspace<const timespec*> user_ts) KResultOr<int> Process::sys$clock_settime(clockid_t clock_id, Userspace<const timespec*> user_ts)
{ {
REQUIRE_PROMISE(settime); REQUIRE_PROMISE(settime);
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
timespec ts; timespec ts;
if (!copy_from_user(&ts, user_ts)) if (!copy_from_user(&ts, user_ts))
return -EFAULT; return EFAULT;
switch (clock_id) { switch (clock_id) {
case CLOCK_REALTIME: case CLOCK_REALTIME:
TimeManagement::the().set_epoch_time(ts); TimeManagement::the().set_epoch_time(ts);
break; break;
default: default:
return -EINVAL; return EINVAL;
} }
return 0; return 0;
} }
int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_params*> user_params) KResultOr<int> Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_params*> user_params)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
Syscall::SC_clock_nanosleep_params params; Syscall::SC_clock_nanosleep_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
timespec requested_sleep; timespec requested_sleep;
if (!copy_from_user(&requested_sleep, params.requested_sleep)) if (!copy_from_user(&requested_sleep, params.requested_sleep))
return -EFAULT; return EFAULT;
bool is_absolute; bool is_absolute;
switch (params.flags) { switch (params.flags) {
@ -85,11 +85,11 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
is_absolute = true; is_absolute = true;
break; break;
default: default:
return -EINVAL; return EINVAL;
} }
if (!TimeManagement::is_valid_clock_id(params.clock_id)) if (!TimeManagement::is_valid_clock_id(params.clock_id))
return -EINVAL; return EINVAL;
bool was_interrupted; bool was_interrupted;
if (is_absolute) { if (is_absolute) {
@ -98,33 +98,33 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
timespec remaining_sleep; timespec remaining_sleep;
was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep, &remaining_sleep).was_interrupted(); was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep, &remaining_sleep).was_interrupted();
if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep)) if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep))
return -EFAULT; return EFAULT;
} }
if (was_interrupted) if (was_interrupted)
return -EINTR; return EINTR;
return 0; return 0;
} }
int Process::sys$adjtime(Userspace<const timeval*> user_delta, Userspace<timeval*> user_old_delta) KResultOr<int> Process::sys$adjtime(Userspace<const timeval*> user_delta, Userspace<timeval*> user_old_delta)
{ {
if (user_old_delta) { if (user_old_delta) {
timespec old_delta_ts = TimeManagement::the().remaining_epoch_time_adjustment(); timespec old_delta_ts = TimeManagement::the().remaining_epoch_time_adjustment();
timeval old_delta; timeval old_delta;
timespec_to_timeval(old_delta_ts, old_delta); timespec_to_timeval(old_delta_ts, old_delta);
if (!copy_to_user(user_old_delta, &old_delta)) if (!copy_to_user(user_old_delta, &old_delta))
return -EFAULT; return EFAULT;
} }
if (user_delta) { if (user_delta) {
REQUIRE_PROMISE(settime); REQUIRE_PROMISE(settime);
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
timeval delta; timeval delta;
if (!copy_from_user(&delta, user_delta)) if (!copy_from_user(&delta, user_delta))
return -EFAULT; return EFAULT;
if (delta.tv_usec < 0 || delta.tv_usec >= 1'000'000) if (delta.tv_usec < 0 || delta.tv_usec >= 1'000'000)
return -EINVAL; return EINVAL;
timespec delta_ts; timespec delta_ts;
timeval_to_timespec(delta, delta_ts); timeval_to_timespec(delta, delta_ts);
@ -134,12 +134,12 @@ int Process::sys$adjtime(Userspace<const timeval*> user_delta, Userspace<timeval
return 0; return 0;
} }
int Process::sys$gettimeofday(Userspace<timeval*> user_tv) KResultOr<int> Process::sys$gettimeofday(Userspace<timeval*> user_tv)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto tv = kgettimeofday(); auto tv = kgettimeofday();
if (!copy_to_user(user_tv, &tv)) if (!copy_to_user(user_tv, &tv))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -31,26 +31,26 @@
namespace Kernel { namespace Kernel {
int Process::sys$dump_backtrace() KResultOr<int> Process::sys$dump_backtrace()
{ {
dump_backtrace(); dump_backtrace();
return 0; return 0;
} }
int Process::sys$dbgputch(u8 ch) KResultOr<int> Process::sys$dbgputch(u8 ch)
{ {
IO::out8(0xe9, ch); IO::out8(0xe9, ch);
return 0; return 0;
} }
int Process::sys$dbgputstr(Userspace<const u8*> characters, int length) KResultOr<int> Process::sys$dbgputstr(Userspace<const u8*> characters, int length)
{ {
if (length <= 0) if (length <= 0)
return 0; return 0;
auto buffer = UserOrKernelBuffer::for_user_buffer(characters, length); auto buffer = UserOrKernelBuffer::for_user_buffer(characters, length);
if (!buffer.has_value()) if (!buffer.has_value())
return -EFAULT; return EFAULT;
ssize_t nread = buffer.value().read_buffered<1024>(length, [&](const u8* buffer, size_t buffer_size) { ssize_t nread = buffer.value().read_buffered<1024>(length, [&](const u8* buffer, size_t buffer_size) {
for (size_t i = 0; i < buffer_size; ++i) for (size_t i = 0; i < buffer_size; ++i)
IO::out8(0xe9, buffer[i]); IO::out8(0xe9, buffer[i]);

View file

@ -28,14 +28,14 @@
namespace Kernel { namespace Kernel {
int Process::sys$disown(ProcessID pid) KResultOr<int> Process::sys$disown(ProcessID pid)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return -ESRCH; return ESRCH;
if (process->ppid() != this->pid()) if (process->ppid() != this->pid())
return -ECHILD; return ECHILD;
process->m_ppid = 0; process->m_ppid = 0;
process->disowned_by_waiter(*this); process->disowned_by_waiter(*this);
return 0; return 0;

View file

@ -29,16 +29,16 @@
namespace Kernel { namespace Kernel {
int Process::sys$dup2(int old_fd, int new_fd) KResultOr<int> Process::sys$dup2(int old_fd, int new_fd)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto description = file_description(old_fd); auto description = file_description(old_fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (old_fd == new_fd) if (old_fd == new_fd)
return 0; return 0;
if (new_fd < 0 || new_fd >= m_max_open_file_descriptors) if (new_fd < 0 || new_fd >= m_max_open_file_descriptors)
return -EINVAL; return EINVAL;
m_fds[new_fd].set(*description); m_fds[new_fd].set(*description);
return new_fd; return new_fd;
} }

View file

@ -214,7 +214,7 @@ static KResultOr<FlatPtr> get_interpreter_load_offset(const Elf32_Ehdr& main_pro
} }
if (main_program_header.e_type != ET_EXEC) if (main_program_header.e_type != ET_EXEC)
return -EINVAL; return EINVAL;
auto main_program_load_range_result = get_required_load_range(main_program_description); auto main_program_load_range_result = get_required_load_range(main_program_description);
if (main_program_load_range_result.is_error()) if (main_program_load_range_result.is_error())
@ -245,7 +245,7 @@ static KResultOr<FlatPtr> get_interpreter_load_offset(const Elf32_Ehdr& main_pro
// If main program is too big and leaves us without enough space for adequate loader randmoization // If main program is too big and leaves us without enough space for adequate loader randmoization
if (selected_range.end - selected_range.start < minimum_interpreter_load_offset_randomization_size) if (selected_range.end - selected_range.start < minimum_interpreter_load_offset_randomization_size)
return -E2BIG; return E2BIG;
return random_load_offset_in_range(selected_range.start, selected_range.end - selected_range.start); return random_load_offset_in_range(selected_range.start, selected_range.end - selected_range.start);
} }
@ -876,7 +876,7 @@ KResult Process::exec(String path, Vector<String> arguments, Vector<String> envi
return KSuccess; return KSuccess;
} }
int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params) KResultOr<int> Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
{ {
REQUIRE_PROMISE(exec); REQUIRE_PROMISE(exec);
@ -884,10 +884,10 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
// On success, the kernel stack will be lost. // On success, the kernel stack will be lost.
Syscall::SC_execve_params params; Syscall::SC_execve_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX) if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
return -E2BIG; return E2BIG;
String path; String path;
{ {
@ -919,11 +919,11 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
Vector<String> arguments; Vector<String> arguments;
if (!copy_user_strings(params.arguments, arguments)) if (!copy_user_strings(params.arguments, arguments))
return -EFAULT; return EFAULT;
Vector<String> environment; Vector<String> environment;
if (!copy_user_strings(params.environment, environment)) if (!copy_user_strings(params.environment, environment))
return -EFAULT; return EFAULT;
auto result = exec(move(path), move(arguments), move(environment)); auto result = exec(move(path), move(arguments), move(environment));
VERIFY(result.is_error()); // We should never continue after a successful exec! VERIFY(result.is_error()); // We should never continue after a successful exec!

View file

@ -30,20 +30,20 @@
namespace Kernel { namespace Kernel {
int Process::sys$fcntl(int fd, int cmd, u32 arg) KResultOr<int> Process::sys$fcntl(int fd, int cmd, u32 arg)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
dbgln_if(IO_DEBUG, "sys$fcntl: fd={}, cmd={}, arg={}", fd, cmd, arg); dbgln_if(IO_DEBUG, "sys$fcntl: fd={}, cmd={}, arg={}", fd, cmd, arg);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
// NOTE: The FD flags are not shared between FileDescription objects. // NOTE: The FD flags are not shared between FileDescription objects.
// This means that dup() doesn't copy the FD_CLOEXEC flag! // This means that dup() doesn't copy the FD_CLOEXEC flag!
switch (cmd) { switch (cmd) {
case F_DUPFD: { case F_DUPFD: {
int arg_fd = (int)arg; int arg_fd = (int)arg;
if (arg_fd < 0) if (arg_fd < 0)
return -EINVAL; return EINVAL;
int new_fd = alloc_fd(arg_fd); int new_fd = alloc_fd(arg_fd);
if (new_fd < 0) if (new_fd < 0)
return new_fd; return new_fd;
@ -63,7 +63,7 @@ int Process::sys$fcntl(int fd, int cmd, u32 arg)
case F_ISTTY: case F_ISTTY:
return description->is_tty(); return description->is_tty();
default: default:
return -EINVAL; return EINVAL;
} }
return 0; return 0;
} }

View file

@ -32,13 +32,13 @@
namespace Kernel { namespace Kernel {
pid_t Process::sys$fork(RegisterState& regs) KResultOr<pid_t> Process::sys$fork(RegisterState& regs)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
RefPtr<Thread> child_first_thread; RefPtr<Thread> child_first_thread;
auto child = adopt(*new Process(child_first_thread, m_name, m_uid, m_gid, m_pid, m_is_kernel_process, m_cwd, m_executable, m_tty, this)); auto child = adopt(*new Process(child_first_thread, m_name, m_uid, m_gid, m_pid, m_is_kernel_process, m_cwd, m_executable, m_tty, this));
if (!child_first_thread) if (!child_first_thread)
return -ENOMEM; return ENOMEM;
child->m_root_directory = m_root_directory; child->m_root_directory = m_root_directory;
child->m_root_directory_relative_to_global_root = m_root_directory_relative_to_global_root; child->m_root_directory_relative_to_global_root = m_root_directory_relative_to_global_root;
child->m_promises = m_promises; child->m_promises = m_promises;
@ -85,7 +85,7 @@ pid_t Process::sys$fork(RegisterState& regs)
if (!region_clone) { if (!region_clone) {
dbgln("fork: Cannot clone region, insufficient memory"); dbgln("fork: Cannot clone region, insufficient memory");
// TODO: tear down new process? // TODO: tear down new process?
return -ENOMEM; return ENOMEM;
} }
auto& child_region = child->space().add_region(region_clone.release_nonnull()); auto& child_region = child->space().add_region(region_clone.release_nonnull());

View file

@ -29,16 +29,16 @@
namespace Kernel { namespace Kernel {
int Process::sys$ftruncate(int fd, off_t length) KResultOr<int> Process::sys$ftruncate(int fd, off_t length)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (length < 0) if (length < 0)
return -EINVAL; return EINVAL;
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_writable()) if (!description->is_writable())
return -EBADF; return EBADF;
return description->truncate(static_cast<u64>(length)); return description->truncate(static_cast<u64>(length));
} }

View file

@ -102,13 +102,13 @@ void Process::clear_futex_queues_on_exec()
m_futex_queues.clear(); m_futex_queues.clear();
} }
int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params) KResultOr<int> Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
{ {
REQUIRE_PROMISE(thread); REQUIRE_PROMISE(thread);
Syscall::SC_futex_params params; Syscall::SC_futex_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
Thread::BlockTimeout timeout; Thread::BlockTimeout timeout;
u32 cmd = params.futex_op & FUTEX_CMD_MASK; u32 cmd = params.futex_op & FUTEX_CMD_MASK;
@ -120,7 +120,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
if (params.timeout) { if (params.timeout) {
timespec ts_stimeout { 0, 0 }; timespec ts_stimeout { 0, 0 };
if (!copy_from_user(&ts_stimeout, params.timeout)) if (!copy_from_user(&ts_stimeout, params.timeout))
return -EFAULT; return EFAULT;
clockid_t clock_id = (params.futex_op & FUTEX_CLOCK_REALTIME) ? CLOCK_REALTIME_COARSE : CLOCK_MONOTONIC_COARSE; clockid_t clock_id = (params.futex_op & FUTEX_CLOCK_REALTIME) ? CLOCK_REALTIME_COARSE : CLOCK_MONOTONIC_COARSE;
bool is_absolute = cmd != FUTEX_WAIT; bool is_absolute = cmd != FUTEX_WAIT;
timeout = Thread::BlockTimeout(is_absolute, &ts_stimeout, nullptr, clock_id); timeout = Thread::BlockTimeout(is_absolute, &ts_stimeout, nullptr, clock_id);
@ -146,7 +146,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
if (!is_private) { if (!is_private) {
auto region = space().find_region_containing(Range { VirtualAddress { user_address_or_offset }, sizeof(u32) }); auto region = space().find_region_containing(Range { VirtualAddress { user_address_or_offset }, sizeof(u32) });
if (!region) if (!region)
return -EFAULT; return EFAULT;
vmobject = region->vmobject(); vmobject = region->vmobject();
user_address_or_offset = region->offset_in_vmobject_from_vaddr(VirtualAddress(user_address_or_offset)); user_address_or_offset = region->offset_in_vmobject_from_vaddr(VirtualAddress(user_address_or_offset));
@ -156,7 +156,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
case FUTEX_WAKE_OP: { case FUTEX_WAKE_OP: {
auto region2 = space().find_region_containing(Range { VirtualAddress { user_address_or_offset2 }, sizeof(u32) }); auto region2 = space().find_region_containing(Range { VirtualAddress { user_address_or_offset2 }, sizeof(u32) });
if (!region2) if (!region2)
return -EFAULT; return EFAULT;
vmobject2 = region2->vmobject(); vmobject2 = region2->vmobject();
user_address_or_offset2 = region->offset_in_vmobject_from_vaddr(VirtualAddress(user_address_or_offset2)); user_address_or_offset2 = region->offset_in_vmobject_from_vaddr(VirtualAddress(user_address_or_offset2));
break; break;
@ -226,10 +226,10 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
auto do_wait = [&](u32 bitset) -> int { auto do_wait = [&](u32 bitset) -> int {
auto user_value = user_atomic_load_relaxed(params.userspace_address); auto user_value = user_atomic_load_relaxed(params.userspace_address);
if (!user_value.has_value()) if (!user_value.has_value())
return -EFAULT; return EFAULT;
if (user_value.value() != params.val) { if (user_value.value() != params.val) {
dbgln("futex wait: EAGAIN. user value: {:p} @ {:p} != val: {}", user_value.value(), params.userspace_address, params.val); dbgln("futex wait: EAGAIN. user value: {:p} @ {:p} != val: {}", user_value.value(), params.userspace_address, params.val);
return -EAGAIN; return EAGAIN;
} }
atomic_thread_fence(AK::MemoryOrder::memory_order_acquire); atomic_thread_fence(AK::MemoryOrder::memory_order_acquire);
@ -248,7 +248,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
remove_futex_queue(vmobject, user_address_or_offset); remove_futex_queue(vmobject, user_address_or_offset);
} }
if (block_result == Thread::BlockResult::InterruptedByTimeout) { if (block_result == Thread::BlockResult::InterruptedByTimeout) {
return -ETIMEDOUT; return ETIMEDOUT;
} }
return 0; return 0;
}; };
@ -256,9 +256,9 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
auto do_requeue = [&](Optional<u32> val3) -> int { auto do_requeue = [&](Optional<u32> val3) -> int {
auto user_value = user_atomic_load_relaxed(params.userspace_address); auto user_value = user_atomic_load_relaxed(params.userspace_address);
if (!user_value.has_value()) if (!user_value.has_value())
return -EFAULT; return EFAULT;
if (val3.has_value() && val3.value() != user_value.value()) if (val3.has_value() && val3.value() != user_value.value())
return -EAGAIN; return EAGAIN;
atomic_thread_fence(AK::MemoryOrder::memory_order_acquire); atomic_thread_fence(AK::MemoryOrder::memory_order_acquire);
int woken_or_requeued = 0; int woken_or_requeued = 0;
@ -315,10 +315,10 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
oldval = user_atomic_fetch_xor_relaxed(params.userspace_address2, op_arg); oldval = user_atomic_fetch_xor_relaxed(params.userspace_address2, op_arg);
break; break;
default: default:
return -EINVAL; return EINVAL;
} }
if (!oldval.has_value()) if (!oldval.has_value())
return -EFAULT; return EFAULT;
atomic_thread_fence(AK::MemoryOrder::memory_order_acquire); atomic_thread_fence(AK::MemoryOrder::memory_order_acquire);
int result = do_wake(vmobject.ptr(), user_address_or_offset, params.val, {}); int result = do_wake(vmobject.ptr(), user_address_or_offset, params.val, {});
if (params.val2 > 0) { if (params.val2 > 0) {
@ -343,7 +343,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
compare_result = (oldval.value() >= _FUTEX_CMP_ARG(params.val3)); compare_result = (oldval.value() >= _FUTEX_CMP_ARG(params.val3));
break; break;
default: default:
return -EINVAL; return EINVAL;
} }
if (compare_result) if (compare_result)
result += do_wake(vmobject2.ptr(), user_address_or_offset2, params.val2, {}); result += do_wake(vmobject2.ptr(), user_address_or_offset2, params.val2, {});
@ -360,16 +360,16 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
case FUTEX_WAIT_BITSET: case FUTEX_WAIT_BITSET:
VERIFY(params.val3 != FUTEX_BITSET_MATCH_ANY); // we should have turned it into FUTEX_WAIT VERIFY(params.val3 != FUTEX_BITSET_MATCH_ANY); // we should have turned it into FUTEX_WAIT
if (params.val3 == 0) if (params.val3 == 0)
return -EINVAL; return EINVAL;
return do_wait(params.val3); return do_wait(params.val3);
case FUTEX_WAKE_BITSET: case FUTEX_WAKE_BITSET:
VERIFY(params.val3 != FUTEX_BITSET_MATCH_ANY); // we should have turned it into FUTEX_WAKE VERIFY(params.val3 != FUTEX_BITSET_MATCH_ANY); // we should have turned it into FUTEX_WAKE
if (params.val3 == 0) if (params.val3 == 0)
return -EINVAL; return EINVAL;
return do_wake(vmobject.ptr(), user_address_or_offset, params.val, params.val3); return do_wake(vmobject.ptr(), user_address_or_offset, params.val, params.val3);
} }
return -ENOSYS; return ENOSYS;
} }
} }

View file

@ -29,17 +29,17 @@
namespace Kernel { namespace Kernel {
ssize_t Process::sys$get_dir_entries(int fd, void* buffer, ssize_t size) KResultOr<ssize_t> Process::sys$get_dir_entries(int fd, void* buffer, ssize_t size)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (size < 0) if (size < 0)
return -EINVAL; return EINVAL;
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
auto user_buffer = UserOrKernelBuffer::for_user_buffer((u8*)buffer, size); auto user_buffer = UserOrKernelBuffer::for_user_buffer((u8*)buffer, size);
if (!user_buffer.has_value()) if (!user_buffer.has_value())
return -EFAULT; return EFAULT;
return description->get_dir_entries(user_buffer.value(), size); return description->get_dir_entries(user_buffer.value(), size);
} }

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_size) KResultOr<int> Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_size)
{ {
FlatPtr stack_pointer = Thread::current()->get_register_dump_from_stack().userspace_esp; FlatPtr stack_pointer = Thread::current()->get_register_dump_from_stack().userspace_esp;
auto* stack_region = space().find_region_containing(Range { VirtualAddress(stack_pointer), 1 }); auto* stack_region = space().find_region_containing(Range { VirtualAddress(stack_pointer), 1 });
@ -41,9 +41,9 @@ int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_s
FlatPtr stack_base = stack_region->range().base().get(); FlatPtr stack_base = stack_region->range().base().get();
size_t stack_size = stack_region->size(); size_t stack_size = stack_region->size();
if (!copy_to_user(user_stack_base, &stack_base)) if (!copy_to_user(user_stack_base, &stack_base))
return -EFAULT; return EFAULT;
if (!copy_to_user(user_stack_size, &stack_size)) if (!copy_to_user(user_stack_size, &stack_size))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -33,15 +33,15 @@ namespace Kernel {
// We don't use the flag yet, but we could use it for distinguishing // We don't use the flag yet, but we could use it for distinguishing
// random source like Linux, unlike the OpenBSD equivalent. However, if we // random source like Linux, unlike the OpenBSD equivalent. However, if we
// do, we should be able of the caveats that Linux has dealt with. // do, we should be able of the caveats that Linux has dealt with.
ssize_t Process::sys$getrandom(Userspace<void*> buffer, size_t buffer_size, [[maybe_unused]] unsigned flags) KResultOr<ssize_t> Process::sys$getrandom(Userspace<void*> buffer, size_t buffer_size, [[maybe_unused]] unsigned flags)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (buffer_size <= 0) if (buffer_size <= 0)
return -EINVAL; return EINVAL;
auto data_buffer = UserOrKernelBuffer::for_user_buffer(buffer, buffer_size); auto data_buffer = UserOrKernelBuffer::for_user_buffer(buffer, buffer_size);
if (!data_buffer.has_value()) if (!data_buffer.has_value())
return -EFAULT; return EFAULT;
ssize_t nwritten = data_buffer.value().write_buffered<1024>(buffer_size, [&](u8* buffer, size_t buffer_bytes) { ssize_t nwritten = data_buffer.value().write_buffered<1024>(buffer_size, [&](u8* buffer, size_t buffer_bytes) {
get_good_random_bytes(buffer, buffer_bytes); get_good_random_bytes(buffer, buffer_bytes);
return (ssize_t)buffer_bytes; return (ssize_t)buffer_bytes;

View file

@ -28,58 +28,58 @@
namespace Kernel { namespace Kernel {
uid_t Process::sys$getuid() KResultOr<uid_t> Process::sys$getuid()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return m_uid; return m_uid;
} }
gid_t Process::sys$getgid() KResultOr<gid_t> Process::sys$getgid()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return m_gid; return m_gid;
} }
uid_t Process::sys$geteuid() KResultOr<uid_t> Process::sys$geteuid()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return m_euid; return m_euid;
} }
gid_t Process::sys$getegid() KResultOr<gid_t> Process::sys$getegid()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return m_egid; return m_egid;
} }
int Process::sys$getresuid(Userspace<uid_t*> ruid, Userspace<uid_t*> euid, Userspace<uid_t*> suid) KResultOr<int> Process::sys$getresuid(Userspace<uid_t*> ruid, Userspace<uid_t*> euid, Userspace<uid_t*> suid)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (!copy_to_user(ruid, &m_uid) || !copy_to_user(euid, &m_euid) || !copy_to_user(suid, &m_suid)) if (!copy_to_user(ruid, &m_uid) || !copy_to_user(euid, &m_euid) || !copy_to_user(suid, &m_suid))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$getresgid(Userspace<gid_t*> rgid, Userspace<gid_t*> egid, Userspace<gid_t*> sgid) KResultOr<int> Process::sys$getresgid(Userspace<gid_t*> rgid, Userspace<gid_t*> egid, Userspace<gid_t*> sgid)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (!copy_to_user(rgid, &m_gid) || !copy_to_user(egid, &m_egid) || !copy_to_user(sgid, &m_sgid)) if (!copy_to_user(rgid, &m_gid) || !copy_to_user(egid, &m_egid) || !copy_to_user(sgid, &m_sgid))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$getgroups(ssize_t count, Userspace<gid_t*> user_gids) KResultOr<int> Process::sys$getgroups(ssize_t count, Userspace<gid_t*> user_gids)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (count < 0) if (count < 0)
return -EINVAL; return EINVAL;
if (!count) if (!count)
return m_extra_gids.size(); return m_extra_gids.size();
if (count != (int)m_extra_gids.size()) if (count != (int)m_extra_gids.size())
return -EINVAL; return EINVAL;
if (!copy_to_user(user_gids, m_extra_gids.data(), sizeof(gid_t) * count)) if (!copy_to_user(user_gids, m_extra_gids.data(), sizeof(gid_t) * count))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -31,32 +31,32 @@ namespace Kernel {
extern String* g_hostname; extern String* g_hostname;
extern Lock* g_hostname_lock; extern Lock* g_hostname_lock;
int Process::sys$gethostname(Userspace<char*> buffer, ssize_t size) KResultOr<int> Process::sys$gethostname(Userspace<char*> buffer, ssize_t size)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (size < 0) if (size < 0)
return -EINVAL; return EINVAL;
LOCKER(*g_hostname_lock, Lock::Mode::Shared); LOCKER(*g_hostname_lock, Lock::Mode::Shared);
if ((size_t)size < (g_hostname->length() + 1)) if ((size_t)size < (g_hostname->length() + 1))
return -ENAMETOOLONG; return ENAMETOOLONG;
if (!copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1)) if (!copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$sethostname(Userspace<const char*> hostname, ssize_t length) KResultOr<int> Process::sys$sethostname(Userspace<const char*> hostname, ssize_t length)
{ {
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
if (length < 0) if (length < 0)
return -EINVAL; return EINVAL;
LOCKER(*g_hostname_lock, Lock::Mode::Exclusive); LOCKER(*g_hostname_lock, Lock::Mode::Exclusive);
if (length > 64) if (length > 64)
return -ENAMETOOLONG; return ENAMETOOLONG;
auto copied_hostname = copy_string_from_user(hostname, length); auto copied_hostname = copy_string_from_user(hostname, length);
if (copied_hostname.is_null()) if (copied_hostname.is_null())
return -EFAULT; return EFAULT;
*g_hostname = move(copied_hostname); *g_hostname = move(copied_hostname);
return 0; return 0;
} }

View file

@ -29,11 +29,11 @@
namespace Kernel { namespace Kernel {
int Process::sys$ioctl(int fd, unsigned request, FlatPtr arg) KResultOr<int> Process::sys$ioctl(int fd, unsigned request, FlatPtr arg)
{ {
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
return description->file().ioctl(*description, request, arg); return description->file().ioctl(*description, request, arg);
} }

View file

@ -31,68 +31,68 @@ namespace Kernel {
constexpr size_t map_name_max_size = 50; constexpr size_t map_name_max_size = 50;
int Process::sys$setkeymap(Userspace<const Syscall::SC_setkeymap_params*> user_params) KResultOr<int> Process::sys$setkeymap(Userspace<const Syscall::SC_setkeymap_params*> user_params)
{ {
REQUIRE_PROMISE(setkeymap); REQUIRE_PROMISE(setkeymap);
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
Syscall::SC_setkeymap_params params; Syscall::SC_setkeymap_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
Keyboard::CharacterMapData character_map_data; Keyboard::CharacterMapData character_map_data;
if (!copy_n_from_user(character_map_data.map, params.map, CHAR_MAP_SIZE)) if (!copy_n_from_user(character_map_data.map, params.map, CHAR_MAP_SIZE))
return -EFAULT; return EFAULT;
if (!copy_n_from_user(character_map_data.shift_map, params.shift_map, CHAR_MAP_SIZE)) if (!copy_n_from_user(character_map_data.shift_map, params.shift_map, CHAR_MAP_SIZE))
return -EFAULT; return EFAULT;
if (!copy_n_from_user(character_map_data.alt_map, params.alt_map, CHAR_MAP_SIZE)) if (!copy_n_from_user(character_map_data.alt_map, params.alt_map, CHAR_MAP_SIZE))
return -EFAULT; return EFAULT;
if (!copy_n_from_user(character_map_data.altgr_map, params.altgr_map, CHAR_MAP_SIZE)) if (!copy_n_from_user(character_map_data.altgr_map, params.altgr_map, CHAR_MAP_SIZE))
return -EFAULT; return EFAULT;
if (!copy_n_from_user(character_map_data.shift_altgr_map, params.shift_altgr_map, CHAR_MAP_SIZE)) if (!copy_n_from_user(character_map_data.shift_altgr_map, params.shift_altgr_map, CHAR_MAP_SIZE))
return -EFAULT; return EFAULT;
auto map_name = get_syscall_path_argument(params.map_name); auto map_name = get_syscall_path_argument(params.map_name);
if (map_name.is_error()) { if (map_name.is_error()) {
return map_name.error(); return map_name.error();
} }
if (map_name.value().length() > map_name_max_size) { if (map_name.value().length() > map_name_max_size) {
return -ENAMETOOLONG; return ENAMETOOLONG;
} }
KeyboardDevice::the().set_maps(character_map_data, map_name.value()); KeyboardDevice::the().set_maps(character_map_data, map_name.value());
return 0; return 0;
} }
int Process::sys$getkeymap(Userspace<const Syscall::SC_getkeymap_params*> user_params) KResultOr<int> Process::sys$getkeymap(Userspace<const Syscall::SC_getkeymap_params*> user_params)
{ {
REQUIRE_PROMISE(getkeymap); REQUIRE_PROMISE(getkeymap);
Syscall::SC_getkeymap_params params; Syscall::SC_getkeymap_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
String keymap_name = KeyboardDevice::the().keymap_name(); String keymap_name = KeyboardDevice::the().keymap_name();
const Keyboard::CharacterMapData& character_maps = KeyboardDevice::the().character_maps(); const Keyboard::CharacterMapData& character_maps = KeyboardDevice::the().character_maps();
if (!copy_to_user(params.map, character_maps.map, CHAR_MAP_SIZE * sizeof(u32))) if (!copy_to_user(params.map, character_maps.map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT; return EFAULT;
if (!copy_to_user(params.shift_map, character_maps.shift_map, CHAR_MAP_SIZE * sizeof(u32))) if (!copy_to_user(params.shift_map, character_maps.shift_map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT; return EFAULT;
if (!copy_to_user(params.alt_map, character_maps.alt_map, CHAR_MAP_SIZE * sizeof(u32))) if (!copy_to_user(params.alt_map, character_maps.alt_map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT; return EFAULT;
if (!copy_to_user(params.altgr_map, character_maps.altgr_map, CHAR_MAP_SIZE * sizeof(u32))) if (!copy_to_user(params.altgr_map, character_maps.altgr_map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT; return EFAULT;
if (!copy_to_user(params.shift_altgr_map, character_maps.shift_altgr_map, CHAR_MAP_SIZE * sizeof(u32))) if (!copy_to_user(params.shift_altgr_map, character_maps.shift_altgr_map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT; return EFAULT;
if (params.map_name.size < keymap_name.length()) if (params.map_name.size < keymap_name.length())
return -ENAMETOOLONG; return ENAMETOOLONG;
if (!copy_to_user(params.map_name.data, keymap_name.characters(), keymap_name.length())) if (!copy_to_user(params.map_name.data, keymap_name.characters(), keymap_name.length()))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -117,7 +117,7 @@ KResult Process::do_killself(int signal)
return KSuccess; return KSuccess;
} }
int Process::sys$kill(pid_t pid_or_pgid, int signal) KResultOr<int> Process::sys$kill(pid_t pid_or_pgid, int signal)
{ {
if (pid_or_pgid == m_pid.value()) if (pid_or_pgid == m_pid.value())
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
@ -125,10 +125,10 @@ int Process::sys$kill(pid_t pid_or_pgid, int signal)
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
if (signal < 0 || signal >= 32) if (signal < 0 || signal >= 32)
return -EINVAL; return EINVAL;
if (pid_or_pgid < -1) { if (pid_or_pgid < -1) {
if (pid_or_pgid == NumericLimits<i32>::min()) if (pid_or_pgid == NumericLimits<i32>::min())
return -EINVAL; return EINVAL;
return do_killpg(-pid_or_pgid, signal); return do_killpg(-pid_or_pgid, signal);
} }
if (pid_or_pgid == -1) if (pid_or_pgid == -1)
@ -140,17 +140,17 @@ int Process::sys$kill(pid_t pid_or_pgid, int signal)
ScopedSpinLock lock(g_processes_lock); ScopedSpinLock lock(g_processes_lock);
auto peer = Process::from_pid(pid_or_pgid); auto peer = Process::from_pid(pid_or_pgid);
if (!peer) if (!peer)
return -ESRCH; return ESRCH;
return do_kill(*peer, signal); return do_kill(*peer, signal);
} }
int Process::sys$killpg(pid_t pgrp, int signum) KResultOr<int> Process::sys$killpg(pid_t pgrp, int signum)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
if (signum < 1 || signum >= 32) if (signum < 1 || signum >= 32)
return -EINVAL; return EINVAL;
if (pgrp < 0) if (pgrp < 0)
return -EINVAL; return EINVAL;
return do_killpg(pgrp, signum); return do_killpg(pgrp, signum);
} }

View file

@ -30,27 +30,27 @@
namespace Kernel { namespace Kernel {
int Process::sys$link(Userspace<const Syscall::SC_link_params*> user_params) KResultOr<int> Process::sys$link(Userspace<const Syscall::SC_link_params*> user_params)
{ {
REQUIRE_PROMISE(cpath); REQUIRE_PROMISE(cpath);
Syscall::SC_link_params params; Syscall::SC_link_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto old_path = copy_string_from_user(params.old_path); auto old_path = copy_string_from_user(params.old_path);
if (old_path.is_null()) if (old_path.is_null())
return -EFAULT; return EFAULT;
auto new_path = copy_string_from_user(params.new_path); auto new_path = copy_string_from_user(params.new_path);
if (new_path.is_null()) if (new_path.is_null())
return -EFAULT; return EFAULT;
return VFS::the().link(old_path, new_path, current_directory()); return VFS::the().link(old_path, new_path, current_directory());
} }
int Process::sys$symlink(Userspace<const Syscall::SC_symlink_params*> user_params) KResultOr<int> Process::sys$symlink(Userspace<const Syscall::SC_symlink_params*> user_params)
{ {
REQUIRE_PROMISE(cpath); REQUIRE_PROMISE(cpath);
Syscall::SC_symlink_params params; Syscall::SC_symlink_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto target = get_syscall_path_argument(params.target); auto target = get_syscall_path_argument(params.target);
if (target.is_error()) if (target.is_error())
return target.error(); return target.error();

View file

@ -29,12 +29,12 @@
namespace Kernel { namespace Kernel {
int Process::sys$lseek(int fd, off_t offset, int whence) KResultOr<int> Process::sys$lseek(int fd, off_t offset, int whence)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
return description->seek(offset, whence); return description->seek(offset, whence);
} }

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$mkdir(Userspace<const char*> user_path, size_t path_length, mode_t mode) KResultOr<int> Process::sys$mkdir(Userspace<const char*> user_path, size_t path_length, mode_t mode)
{ {
REQUIRE_PROMISE(cpath); REQUIRE_PROMISE(cpath);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);

View file

@ -30,14 +30,14 @@
namespace Kernel { namespace Kernel {
int Process::sys$mknod(Userspace<const Syscall::SC_mknod_params*> user_params) KResultOr<int> Process::sys$mknod(Userspace<const Syscall::SC_mknod_params*> user_params)
{ {
REQUIRE_PROMISE(dpath); REQUIRE_PROMISE(dpath);
Syscall::SC_mknod_params params; Syscall::SC_mknod_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
if (!is_superuser() && !is_regular_file(params.mode) && !is_fifo(params.mode) && !is_socket(params.mode)) if (!is_superuser() && !is_regular_file(params.mode) && !is_fifo(params.mode) && !is_socket(params.mode))
return -EPERM; return EPERM;
auto path = get_syscall_path_argument(params.path); auto path = get_syscall_path_argument(params.path);
if (path.is_error()) if (path.is_error())
return path.error(); return path.error();

View file

@ -137,13 +137,13 @@ static bool validate_inode_mmap_prot(const Process& process, int prot, const Ino
return true; return true;
} }
FlatPtr Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params) KResultOr<FlatPtr> Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
Syscall::SC_mmap_params params; Syscall::SC_mmap_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
void* addr = (void*)params.addr; void* addr = (void*)params.addr;
size_t size = params.size; size_t size = params.size;
@ -162,27 +162,27 @@ FlatPtr Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
} }
if (alignment & ~PAGE_MASK) if (alignment & ~PAGE_MASK)
return -EINVAL; return EINVAL;
if (page_round_up_would_wrap(size)) if (page_round_up_would_wrap(size))
return -EINVAL; return EINVAL;
if (!is_user_range(VirtualAddress(addr), page_round_up(size))) if (!is_user_range(VirtualAddress(addr), page_round_up(size)))
return -EFAULT; return EFAULT;
String name; String name;
if (params.name.characters) { if (params.name.characters) {
if (params.name.length > PATH_MAX) if (params.name.length > PATH_MAX)
return -ENAMETOOLONG; return ENAMETOOLONG;
name = copy_string_from_user(params.name); name = copy_string_from_user(params.name);
if (name.is_null()) if (name.is_null())
return -EFAULT; return EFAULT;
} }
if (size == 0) if (size == 0)
return -EINVAL; return EINVAL;
if ((FlatPtr)addr & ~PAGE_MASK) if ((FlatPtr)addr & ~PAGE_MASK)
return -EINVAL; return EINVAL;
bool map_shared = flags & MAP_SHARED; bool map_shared = flags & MAP_SHARED;
bool map_anonymous = flags & MAP_ANONYMOUS; bool map_anonymous = flags & MAP_ANONYMOUS;
@ -193,19 +193,19 @@ FlatPtr Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
bool map_randomized = flags & MAP_RANDOMIZED; bool map_randomized = flags & MAP_RANDOMIZED;
if (map_shared && map_private) if (map_shared && map_private)
return -EINVAL; return EINVAL;
if (!map_shared && !map_private) if (!map_shared && !map_private)
return -EINVAL; return EINVAL;
if (map_fixed && map_randomized) if (map_fixed && map_randomized)
return -EINVAL; return EINVAL;
if (!validate_mmap_prot(prot, map_stack, map_anonymous)) if (!validate_mmap_prot(prot, map_stack, map_anonymous))
return -EINVAL; return EINVAL;
if (map_stack && (!map_private || !map_anonymous)) if (map_stack && (!map_private || !map_anonymous))
return -EINVAL; return EINVAL;
Region* region = nullptr; Region* region = nullptr;
Optional<Range> range; Optional<Range> range;
@ -223,7 +223,7 @@ FlatPtr Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
} }
if (!range.has_value()) if (!range.has_value())
return -ENOMEM; return ENOMEM;
if (map_anonymous) { if (map_anonymous) {
auto strategy = map_noreserve ? AllocationStrategy::None : AllocationStrategy::Reserve; auto strategy = map_noreserve ? AllocationStrategy::None : AllocationStrategy::Reserve;
@ -233,24 +233,24 @@ FlatPtr Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
region = region_or_error.value(); region = region_or_error.value();
} else { } else {
if (offset < 0) if (offset < 0)
return -EINVAL; return EINVAL;
if (static_cast<size_t>(offset) & ~PAGE_MASK) if (static_cast<size_t>(offset) & ~PAGE_MASK)
return -EINVAL; return EINVAL;
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (description->is_directory()) if (description->is_directory())
return -ENODEV; return ENODEV;
// Require read access even when read protection is not requested. // Require read access even when read protection is not requested.
if (!description->is_readable()) if (!description->is_readable())
return -EACCES; return EACCES;
if (map_shared) { if (map_shared) {
if ((prot & PROT_WRITE) && !description->is_writable()) if ((prot & PROT_WRITE) && !description->is_writable())
return -EACCES; return EACCES;
} }
if (description->inode()) { if (description->inode()) {
if (!validate_inode_mmap_prot(*this, prot, *description->inode(), map_shared)) if (!validate_inode_mmap_prot(*this, prot, *description->inode(), map_shared))
return -EACCES; return EACCES;
} }
auto region_or_error = description->mmap(*this, range.value(), static_cast<size_t>(offset), prot, map_shared); auto region_or_error = description->mmap(*this, range.value(), static_cast<size_t>(offset), prot, map_shared);
@ -260,7 +260,7 @@ FlatPtr Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
} }
if (!region) if (!region)
return -ENOMEM; return ENOMEM;
region->set_mmap(true); region->set_mmap(true);
if (map_shared) if (map_shared)
region->set_shared(true); region->set_shared(true);
@ -288,7 +288,7 @@ static KResultOr<Range> expand_range_to_page_boundaries(FlatPtr address, size_t
return Range { base, end - base.get() }; return Range { base, end - base.get() };
} }
int Process::sys$mprotect(void* addr, size_t size, int prot) KResultOr<int> Process::sys$mprotect(void* addr, size_t size, int prot)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
@ -302,21 +302,21 @@ int Process::sys$mprotect(void* addr, size_t size, int prot)
auto range_to_mprotect = range_or_error.value(); auto range_to_mprotect = range_or_error.value();
if (!range_to_mprotect.size()) if (!range_to_mprotect.size())
return -EINVAL; return EINVAL;
if (!is_user_range(range_to_mprotect)) if (!is_user_range(range_to_mprotect))
return -EFAULT; return EFAULT;
if (auto* whole_region = space().find_region_from_range(range_to_mprotect)) { if (auto* whole_region = space().find_region_from_range(range_to_mprotect)) {
if (!whole_region->is_mmap()) if (!whole_region->is_mmap())
return -EPERM; return EPERM;
if (!validate_mmap_prot(prot, whole_region->is_stack(), whole_region->vmobject().is_anonymous(), whole_region)) if (!validate_mmap_prot(prot, whole_region->is_stack(), whole_region->vmobject().is_anonymous(), whole_region))
return -EINVAL; return EINVAL;
if (whole_region->access() == prot_to_region_access_flags(prot)) if (whole_region->access() == prot_to_region_access_flags(prot))
return 0; return 0;
if (whole_region->vmobject().is_inode() if (whole_region->vmobject().is_inode()
&& !validate_inode_mmap_prot(*this, prot, static_cast<const InodeVMObject&>(whole_region->vmobject()).inode(), whole_region->is_shared())) { && !validate_inode_mmap_prot(*this, prot, static_cast<const InodeVMObject&>(whole_region->vmobject()).inode(), whole_region->is_shared())) {
return -EACCES; return EACCES;
} }
whole_region->set_readable(prot & PROT_READ); whole_region->set_readable(prot & PROT_READ);
whole_region->set_writable(prot & PROT_WRITE); whole_region->set_writable(prot & PROT_WRITE);
@ -329,14 +329,14 @@ int Process::sys$mprotect(void* addr, size_t size, int prot)
// Check if we can carve out the desired range from an existing region // Check if we can carve out the desired range from an existing region
if (auto* old_region = space().find_region_containing(range_to_mprotect)) { if (auto* old_region = space().find_region_containing(range_to_mprotect)) {
if (!old_region->is_mmap()) if (!old_region->is_mmap())
return -EPERM; return EPERM;
if (!validate_mmap_prot(prot, old_region->is_stack(), old_region->vmobject().is_anonymous(), old_region)) if (!validate_mmap_prot(prot, old_region->is_stack(), old_region->vmobject().is_anonymous(), old_region))
return -EINVAL; return EINVAL;
if (old_region->access() == prot_to_region_access_flags(prot)) if (old_region->access() == prot_to_region_access_flags(prot))
return 0; return 0;
if (old_region->vmobject().is_inode() if (old_region->vmobject().is_inode()
&& !validate_inode_mmap_prot(*this, prot, static_cast<const InodeVMObject&>(old_region->vmobject()).inode(), old_region->is_shared())) { && !validate_inode_mmap_prot(*this, prot, static_cast<const InodeVMObject&>(old_region->vmobject()).inode(), old_region->is_shared())) {
return -EACCES; return EACCES;
} }
// This vector is the region(s) adjacent to our range. // This vector is the region(s) adjacent to our range.
@ -363,10 +363,10 @@ int Process::sys$mprotect(void* addr, size_t size, int prot)
// FIXME: We should also support mprotect() across multiple regions. (#175) (#964) // FIXME: We should also support mprotect() across multiple regions. (#175) (#964)
return -EINVAL; return EINVAL;
} }
int Process::sys$madvise(void* address, size_t size, int advice) KResultOr<int> Process::sys$madvise(void* address, size_t size, int advice)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
@ -377,31 +377,31 @@ int Process::sys$madvise(void* address, size_t size, int advice)
auto range_to_madvise = range_or_error.value(); auto range_to_madvise = range_or_error.value();
if (!range_to_madvise.size()) if (!range_to_madvise.size())
return -EINVAL; return EINVAL;
if (!is_user_range(range_to_madvise)) if (!is_user_range(range_to_madvise))
return -EFAULT; return EFAULT;
auto* region = space().find_region_from_range(range_to_madvise); auto* region = space().find_region_from_range(range_to_madvise);
if (!region) if (!region)
return -EINVAL; return EINVAL;
if (!region->is_mmap()) if (!region->is_mmap())
return -EPERM; return EPERM;
bool set_volatile = advice & MADV_SET_VOLATILE; bool set_volatile = advice & MADV_SET_VOLATILE;
bool set_nonvolatile = advice & MADV_SET_NONVOLATILE; bool set_nonvolatile = advice & MADV_SET_NONVOLATILE;
if (set_volatile && set_nonvolatile) if (set_volatile && set_nonvolatile)
return -EINVAL; return EINVAL;
if (set_volatile || set_nonvolatile) { if (set_volatile || set_nonvolatile) {
if (!region->vmobject().is_anonymous()) if (!region->vmobject().is_anonymous())
return -EPERM; return EPERM;
bool was_purged = false; bool was_purged = false;
switch (region->set_volatile(VirtualAddress(address), size, set_volatile, was_purged)) { switch (region->set_volatile(VirtualAddress(address), size, set_volatile, was_purged)) {
case Region::SetVolatileError::Success: case Region::SetVolatileError::Success:
break; break;
case Region::SetVolatileError::NotPurgeable: case Region::SetVolatileError::NotPurgeable:
return -EPERM; return EPERM;
case Region::SetVolatileError::OutOfMemory: case Region::SetVolatileError::OutOfMemory:
return -ENOMEM; return ENOMEM;
} }
if (set_nonvolatile) if (set_nonvolatile)
return was_purged ? 1 : 0; return was_purged ? 1 : 0;
@ -409,26 +409,26 @@ int Process::sys$madvise(void* address, size_t size, int advice)
} }
if (advice & MADV_GET_VOLATILE) { if (advice & MADV_GET_VOLATILE) {
if (!region->vmobject().is_anonymous()) if (!region->vmobject().is_anonymous())
return -EPERM; return EPERM;
return region->is_volatile(VirtualAddress(address), size) ? 0 : 1; return region->is_volatile(VirtualAddress(address), size) ? 0 : 1;
} }
return -EINVAL; return EINVAL;
} }
int Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*> user_params) KResultOr<int> Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*> user_params)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
Syscall::SC_set_mmap_name_params params; Syscall::SC_set_mmap_name_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
if (params.name.length > PATH_MAX) if (params.name.length > PATH_MAX)
return -ENAMETOOLONG; return ENAMETOOLONG;
auto name = copy_string_from_user(params.name); auto name = copy_string_from_user(params.name);
if (name.is_null()) if (name.is_null())
return -EFAULT; return EFAULT;
auto range_or_error = expand_range_to_page_boundaries((FlatPtr)params.addr, params.size); auto range_or_error = expand_range_to_page_boundaries((FlatPtr)params.addr, params.size);
if (range_or_error.is_error()) if (range_or_error.is_error())
@ -438,19 +438,19 @@ int Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*
auto* region = space().find_region_from_range(range); auto* region = space().find_region_from_range(range);
if (!region) if (!region)
return -EINVAL; return EINVAL;
if (!region->is_mmap()) if (!region->is_mmap())
return -EPERM; return EPERM;
region->set_name(move(name)); region->set_name(move(name));
return 0; return 0;
} }
int Process::sys$munmap(void* addr, size_t size) KResultOr<int> Process::sys$munmap(void* addr, size_t size)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (!size) if (!size)
return -EINVAL; return EINVAL;
auto range_or_error = expand_range_to_page_boundaries((FlatPtr)addr, size); auto range_or_error = expand_range_to_page_boundaries((FlatPtr)addr, size);
if (range_or_error.is_error()) if (range_or_error.is_error())
@ -459,11 +459,11 @@ int Process::sys$munmap(void* addr, size_t size)
auto range_to_unmap = range_or_error.value(); auto range_to_unmap = range_or_error.value();
if (!is_user_range(range_to_unmap)) if (!is_user_range(range_to_unmap))
return -EFAULT; return EFAULT;
if (auto* whole_region = space().find_region_from_range(range_to_unmap)) { if (auto* whole_region = space().find_region_from_range(range_to_unmap)) {
if (!whole_region->is_mmap()) if (!whole_region->is_mmap())
return -EPERM; return EPERM;
bool success = space().deallocate_region(*whole_region); bool success = space().deallocate_region(*whole_region);
VERIFY(success); VERIFY(success);
return 0; return 0;
@ -471,7 +471,7 @@ int Process::sys$munmap(void* addr, size_t size)
if (auto* old_region = space().find_region_containing(range_to_unmap)) { if (auto* old_region = space().find_region_containing(range_to_unmap)) {
if (!old_region->is_mmap()) if (!old_region->is_mmap())
return -EPERM; return EPERM;
auto new_regions = space().split_region_around_range(*old_region, range_to_unmap); auto new_regions = space().split_region_around_range(*old_region, range_to_unmap);
@ -491,16 +491,16 @@ int Process::sys$munmap(void* addr, size_t size)
// FIXME: We should also support munmap() across multiple regions. (#175) // FIXME: We should also support munmap() across multiple regions. (#175)
return -EINVAL; return EINVAL;
} }
FlatPtr Process::sys$mremap(Userspace<const Syscall::SC_mremap_params*> user_params) KResultOr<FlatPtr> Process::sys$mremap(Userspace<const Syscall::SC_mremap_params*> user_params)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
Syscall::SC_mremap_params params {}; Syscall::SC_mremap_params params {};
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto range_or_error = expand_range_to_page_boundaries((FlatPtr)params.old_address, params.old_size); auto range_or_error = expand_range_to_page_boundaries((FlatPtr)params.old_address, params.old_size);
if (range_or_error.is_error()) if (range_or_error.is_error())
@ -510,10 +510,10 @@ FlatPtr Process::sys$mremap(Userspace<const Syscall::SC_mremap_params*> user_par
auto* old_region = space().find_region_from_range(old_range); auto* old_region = space().find_region_from_range(old_range);
if (!old_region) if (!old_region)
return -EINVAL; return EINVAL;
if (!old_region->is_mmap()) if (!old_region->is_mmap())
return -EPERM; return EPERM;
if (old_region->vmobject().is_shared_inode() && params.flags & MAP_PRIVATE && !(params.flags & (MAP_ANONYMOUS | MAP_NORESERVE))) { if (old_region->vmobject().is_shared_inode() && params.flags & MAP_PRIVATE && !(params.flags & (MAP_ANONYMOUS | MAP_NORESERVE))) {
auto range = old_region->range(); auto range = old_region->range();
@ -536,21 +536,21 @@ FlatPtr Process::sys$mremap(Userspace<const Syscall::SC_mremap_params*> user_par
} }
dbgln("sys$mremap: Unimplemented remap request (flags={})", params.flags); dbgln("sys$mremap: Unimplemented remap request (flags={})", params.flags);
return -ENOTIMPL; return ENOTIMPL;
} }
FlatPtr Process::sys$allocate_tls(size_t size) KResultOr<FlatPtr> Process::sys$allocate_tls(size_t size)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (!size) if (!size)
return -EINVAL; return EINVAL;
if (!m_master_tls_region.is_null()) if (!m_master_tls_region.is_null())
return -EEXIST; return EEXIST;
if (thread_count() != 1) if (thread_count() != 1)
return -EFAULT; return EFAULT;
Thread* main_thread = nullptr; Thread* main_thread = nullptr;
for_each_thread([&main_thread](auto& thread) { for_each_thread([&main_thread](auto& thread) {
@ -561,7 +561,7 @@ FlatPtr Process::sys$allocate_tls(size_t size)
auto range = space().allocate_range({}, size); auto range = space().allocate_range({}, size);
if (!range.has_value()) if (!range.has_value())
return -ENOMEM; return ENOMEM;
auto region_or_error = space().allocate_region(range.value(), String(), PROT_READ | PROT_WRITE); auto region_or_error = space().allocate_region(range.value(), String(), PROT_READ | PROT_WRITE);
if (region_or_error.is_error()) if (region_or_error.is_error())
@ -573,7 +573,7 @@ FlatPtr Process::sys$allocate_tls(size_t size)
auto tsr_result = main_thread->make_thread_specific_region({}); auto tsr_result = main_thread->make_thread_specific_region({});
if (tsr_result.is_error()) if (tsr_result.is_error())
return -EFAULT; return EFAULT;
auto& tls_descriptor = Processor::current().get_gdt_entry(GDT_SELECTOR_TLS); auto& tls_descriptor = Processor::current().get_gdt_entry(GDT_SELECTOR_TLS);
tls_descriptor.set_base(main_thread->thread_specific_data()); tls_descriptor.set_base(main_thread->thread_specific_data());
@ -582,10 +582,10 @@ FlatPtr Process::sys$allocate_tls(size_t size)
return m_master_tls_region.unsafe_ptr()->vaddr().get(); return m_master_tls_region.unsafe_ptr()->vaddr().get();
} }
int Process::sys$msyscall(void* address) KResultOr<int> Process::sys$msyscall(void* address)
{ {
if (space().enforces_syscall_regions()) if (space().enforces_syscall_regions())
return -EPERM; return EPERM;
if (!address) { if (!address) {
space().set_enforces_syscall_regions(true); space().set_enforces_syscall_regions(true);
@ -593,14 +593,14 @@ int Process::sys$msyscall(void* address)
} }
if (!is_user_address(VirtualAddress { address })) if (!is_user_address(VirtualAddress { address }))
return -EFAULT; return EFAULT;
auto* region = space().find_region_containing(Range { VirtualAddress { address }, 1 }); auto* region = space().find_region_containing(Range { VirtualAddress { address }, 1 });
if (!region) if (!region)
return -EINVAL; return EINVAL;
if (!region->is_mmap()) if (!region->is_mmap())
return -EINVAL; return EINVAL;
region->set_syscall_region(true); region->set_syscall_region(true);
return 0; return 0;

View file

@ -35,10 +35,10 @@ namespace Kernel {
extern HashMap<String, OwnPtr<Module>>* g_modules; extern HashMap<String, OwnPtr<Module>>* g_modules;
int Process::sys$module_load(Userspace<const char*> user_path, size_t path_length) KResultOr<int> Process::sys$module_load(Userspace<const char*> user_path, size_t path_length)
{ {
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;
@ -59,7 +59,7 @@ int Process::sys$module_load(Userspace<const char*> user_path, size_t path_lengt
auto elf_image = make<ELF::Image>(storage.data(), storage.size()); auto elf_image = make<ELF::Image>(storage.data(), storage.size());
if (!elf_image->parse()) if (!elf_image->parse())
return -ENOEXEC; return ENOEXEC;
HashMap<String, u8*> section_storage_by_name; HashMap<String, u8*> section_storage_by_name;
@ -124,12 +124,12 @@ int Process::sys$module_load(Userspace<const char*> user_path, size_t path_lengt
}); });
if (missing_symbols) if (missing_symbols)
return -EINVAL; return EINVAL;
auto* text_base = section_storage_by_name.get(".text").value_or(nullptr); auto* text_base = section_storage_by_name.get(".text").value_or(nullptr);
if (!text_base) { if (!text_base) {
dbgln("No .text section found in module!"); dbgln("No .text section found in module!");
return -EINVAL; return EINVAL;
} }
elf_image->for_each_symbol([&](const ELF::Image::Symbol& symbol) { elf_image->for_each_symbol([&](const ELF::Image::Symbol& symbol) {
@ -147,11 +147,11 @@ int Process::sys$module_load(Userspace<const char*> user_path, size_t path_lengt
}); });
if (!module->module_init) if (!module->module_init)
return -EINVAL; return EINVAL;
if (g_modules->contains(module->name)) { if (g_modules->contains(module->name)) {
dbgln("a module with the name {} is already loaded; please unload it first", module->name); dbgln("a module with the name {} is already loaded; please unload it first", module->name);
return -EEXIST; return EEXIST;
} }
module->module_init(); module->module_init();
@ -162,20 +162,20 @@ int Process::sys$module_load(Userspace<const char*> user_path, size_t path_lengt
return 0; return 0;
} }
int Process::sys$module_unload(Userspace<const char*> user_name, size_t name_length) KResultOr<int> Process::sys$module_unload(Userspace<const char*> user_name, size_t name_length)
{ {
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;
auto module_name = copy_string_from_user(user_name, name_length); auto module_name = copy_string_from_user(user_name, name_length);
if (module_name.is_null()) if (module_name.is_null())
return -EFAULT; return EFAULT;
auto it = g_modules->find(module_name); auto it = g_modules->find(module_name);
if (it == g_modules->end()) if (it == g_modules->end())
return -ENOENT; return ENOENT;
if (it->value->module_fini) if (it->value->module_fini)
it->value->module_fini(); it->value->module_fini();

View file

@ -36,24 +36,24 @@
namespace Kernel { namespace Kernel {
int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params) KResultOr<int> Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
{ {
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;
Syscall::SC_mount_params params; Syscall::SC_mount_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto source_fd = params.source_fd; auto source_fd = params.source_fd;
auto target = copy_string_from_user(params.target); auto target = copy_string_from_user(params.target);
if (target.is_null()) if (target.is_null())
return -EFAULT; return EFAULT;
auto fs_type = copy_string_from_user(params.fs_type); auto fs_type = copy_string_from_user(params.fs_type);
if (fs_type.is_null()) if (fs_type.is_null())
return -EFAULT; return EFAULT;
auto description = file_description(source_fd); auto description = file_description(source_fd);
if (!description.is_null()) if (!description.is_null())
@ -75,10 +75,10 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
if (params.flags & MS_BIND) { if (params.flags & MS_BIND) {
// We're doing a bind mount. // We're doing a bind mount.
if (description.is_null()) if (description.is_null())
return -EBADF; return EBADF;
if (!description->custody()) { if (!description->custody()) {
// We only support bind-mounting inodes, not arbitrary files. // We only support bind-mounting inodes, not arbitrary files.
return -ENODEV; return ENODEV;
} }
return VFS::the().bind_mount(*description->custody(), target_custody, params.flags); return VFS::the().bind_mount(*description->custody(), target_custody, params.flags);
} }
@ -87,12 +87,12 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
if (fs_type == "ext2" || fs_type == "Ext2FS") { if (fs_type == "ext2" || fs_type == "Ext2FS") {
if (description.is_null()) if (description.is_null())
return -EBADF; return EBADF;
if (!description->file().is_block_device()) if (!description->file().is_block_device())
return -ENOTBLK; return ENOTBLK;
if (!description->file().is_seekable()) { if (!description->file().is_seekable()) {
dbgln("mount: this is not a seekable file"); dbgln("mount: this is not a seekable file");
return -ENODEV; return ENODEV;
} }
dbgln("mount: attempting to mount {} on {}", description->absolute_path(), target); dbgln("mount: attempting to mount {} on {}", description->absolute_path(), target);
@ -100,7 +100,7 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
fs = Ext2FS::create(*description); fs = Ext2FS::create(*description);
} else if (fs_type == "9p" || fs_type == "Plan9FS") { } else if (fs_type == "9p" || fs_type == "Plan9FS") {
if (description.is_null()) if (description.is_null())
return -EBADF; return EBADF;
fs = Plan9FS::create(*description); fs = Plan9FS::create(*description);
} else if (fs_type == "proc" || fs_type == "ProcFS") { } else if (fs_type == "proc" || fs_type == "ProcFS") {
@ -112,12 +112,12 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
} else if (fs_type == "tmp" || fs_type == "TmpFS") { } else if (fs_type == "tmp" || fs_type == "TmpFS") {
fs = TmpFS::create(); fs = TmpFS::create();
} else { } else {
return -ENODEV; return ENODEV;
} }
if (!fs->initialize()) { if (!fs->initialize()) {
dbgln("mount: failed to initialize {} filesystem, fd={}", fs_type, source_fd); dbgln("mount: failed to initialize {} filesystem, fd={}", fs_type, source_fd);
return -ENODEV; return ENODEV;
} }
auto result = VFS::the().mount(fs.release_nonnull(), target_custody, params.flags); auto result = VFS::the().mount(fs.release_nonnull(), target_custody, params.flags);
@ -128,10 +128,10 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
return result; return result;
} }
int Process::sys$umount(Userspace<const char*> user_mountpoint, size_t mountpoint_length) KResultOr<int> Process::sys$umount(Userspace<const char*> user_mountpoint, size_t mountpoint_length)
{ {
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;

View file

@ -32,21 +32,21 @@
namespace Kernel { namespace Kernel {
int Process::sys$open(Userspace<const Syscall::SC_open_params*> user_params) KResultOr<int> Process::sys$open(Userspace<const Syscall::SC_open_params*> user_params)
{ {
Syscall::SC_open_params params; Syscall::SC_open_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
int dirfd = params.dirfd; int dirfd = params.dirfd;
int options = params.options; int options = params.options;
u16 mode = params.mode; u16 mode = params.mode;
if (options & O_NOFOLLOW_NOERROR) if (options & O_NOFOLLOW_NOERROR)
return -EINVAL; return EINVAL;
if (options & O_UNLINK_INTERNAL) if (options & O_UNLINK_INTERNAL)
return -EINVAL; return EINVAL;
if (options & O_WRONLY) if (options & O_WRONLY)
REQUIRE_PROMISE(wpath); REQUIRE_PROMISE(wpath);
@ -74,11 +74,11 @@ int Process::sys$open(Userspace<const Syscall::SC_open_params*> user_params)
} else { } else {
auto base_description = file_description(dirfd); auto base_description = file_description(dirfd);
if (!base_description) if (!base_description)
return -EBADF; return EBADF;
if (!base_description->is_directory()) if (!base_description->is_directory())
return -ENOTDIR; return ENOTDIR;
if (!base_description->custody()) if (!base_description->custody())
return -EINVAL; return EINVAL;
base = base_description->custody(); base = base_description->custody();
} }
@ -88,20 +88,20 @@ int Process::sys$open(Userspace<const Syscall::SC_open_params*> user_params)
auto description = result.value(); auto description = result.value();
if (description->inode() && description->inode()->socket()) if (description->inode() && description->inode()->socket())
return -ENXIO; return ENXIO;
u32 fd_flags = (options & O_CLOEXEC) ? FD_CLOEXEC : 0; u32 fd_flags = (options & O_CLOEXEC) ? FD_CLOEXEC : 0;
m_fds[fd].set(move(description), fd_flags); m_fds[fd].set(move(description), fd_flags);
return fd; return fd;
} }
int Process::sys$close(int fd) KResultOr<int> Process::sys$close(int fd)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto description = file_description(fd); auto description = file_description(fd);
dbgln_if(IO_DEBUG, "sys$close({}) {}", fd, description.ptr()); dbgln_if(IO_DEBUG, "sys$close({}) {}", fd, description.ptr());
if (!description) if (!description)
return -EBADF; return EBADF;
int rc = description->close(); int rc = description->close();
m_fds[fd] = {}; m_fds[fd] = {};
return rc; return rc;

View file

@ -29,7 +29,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2) KResultOr<int> Process::sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2)
{ {
return ensure_perf_events().append(type, arg1, arg2); return ensure_perf_events().append(type, arg1, arg2);
} }

View file

@ -30,14 +30,14 @@
namespace Kernel { namespace Kernel {
int Process::sys$pipe(int pipefd[2], int flags) KResultOr<int> Process::sys$pipe(int pipefd[2], int flags)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (number_of_open_file_descriptors() + 2 > max_open_file_descriptors()) if (number_of_open_file_descriptors() + 2 > max_open_file_descriptors())
return -EMFILE; return EMFILE;
// Reject flags other than O_CLOEXEC. // Reject flags other than O_CLOEXEC.
if ((flags & O_CLOEXEC) != flags) if ((flags & O_CLOEXEC) != flags)
return -EINVAL; return EINVAL;
u32 fd_flags = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0; u32 fd_flags = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0;
auto fifo = FIFO::create(m_uid); auto fifo = FIFO::create(m_uid);
@ -53,13 +53,13 @@ int Process::sys$pipe(int pipefd[2], int flags)
m_fds[reader_fd].set(open_reader_result.release_value(), fd_flags); m_fds[reader_fd].set(open_reader_result.release_value(), fd_flags);
m_fds[reader_fd].description()->set_readable(true); m_fds[reader_fd].description()->set_readable(true);
if (!copy_to_user(&pipefd[0], &reader_fd)) if (!copy_to_user(&pipefd[0], &reader_fd))
return -EFAULT; return EFAULT;
int writer_fd = alloc_fd(); int writer_fd = alloc_fd();
m_fds[writer_fd].set(open_writer_result.release_value(), fd_flags); m_fds[writer_fd].set(open_writer_result.release_value(), fd_flags);
m_fds[writer_fd].description()->set_writable(true); m_fds[writer_fd].description()->set_writable(true);
if (!copy_to_user(&pipefd[1], &writer_fd)) if (!copy_to_user(&pipefd[1], &writer_fd))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -29,27 +29,27 @@
namespace Kernel { namespace Kernel {
int Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*> user_params) KResultOr<int> Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*> user_params)
{ {
Syscall::SC_pledge_params params; Syscall::SC_pledge_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
if (params.promises.length > 1024 || params.execpromises.length > 1024) if (params.promises.length > 1024 || params.execpromises.length > 1024)
return -E2BIG; return E2BIG;
String promises; String promises;
if (params.promises.characters) { if (params.promises.characters) {
promises = copy_string_from_user(params.promises); promises = copy_string_from_user(params.promises);
if (promises.is_null()) if (promises.is_null())
return -EFAULT; return EFAULT;
} }
String execpromises; String execpromises;
if (params.execpromises.characters) { if (params.execpromises.characters) {
execpromises = copy_string_from_user(params.execpromises); execpromises = copy_string_from_user(params.execpromises);
if (execpromises.is_null()) if (execpromises.is_null())
return -EFAULT; return EFAULT;
} }
auto parse_pledge = [&](auto& pledge_spec, u32& mask) { auto parse_pledge = [&](auto& pledge_spec, u32& mask) {
@ -70,9 +70,9 @@ int Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*> user_params)
if (!promises.is_null()) { if (!promises.is_null()) {
u32 new_promises = 0; u32 new_promises = 0;
if (!parse_pledge(promises, new_promises)) if (!parse_pledge(promises, new_promises))
return -EINVAL; return EINVAL;
if (m_promises && (!new_promises || new_promises & ~m_promises)) if (m_promises && (!new_promises || new_promises & ~m_promises))
return -EPERM; return EPERM;
m_has_promises = true; m_has_promises = true;
m_promises = new_promises; m_promises = new_promises;
} }
@ -80,9 +80,9 @@ int Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*> user_params)
if (!execpromises.is_null()) { if (!execpromises.is_null()) {
u32 new_execpromises = 0; u32 new_execpromises = 0;
if (!parse_pledge(execpromises, new_execpromises)) if (!parse_pledge(execpromises, new_execpromises))
return -EINVAL; return EINVAL;
if (m_execpromises && (!new_execpromises || new_execpromises & ~m_execpromises)) if (m_execpromises && (!new_execpromises || new_execpromises & ~m_execpromises))
return -EPERM; return EPERM;
m_has_execpromises = true; m_has_execpromises = true;
m_execpromises = new_execpromises; m_execpromises = new_execpromises;
} }

View file

@ -29,7 +29,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$prctl(int option, FlatPtr arg1, [[maybe_unused]] FlatPtr arg2) KResultOr<int> Process::sys$prctl(int option, FlatPtr arg1, [[maybe_unused]] FlatPtr arg2)
{ {
switch (option) { switch (option) {
case PR_GET_DUMPABLE: case PR_GET_DUMPABLE:
@ -38,7 +38,7 @@ int Process::sys$prctl(int option, FlatPtr arg1, [[maybe_unused]] FlatPtr arg2)
set_dumpable(arg1); set_dumpable(arg1);
return 0; return 0;
default: default:
return -EINVAL; return EINVAL;
} }
return 0; return 0;
} }

View file

@ -29,61 +29,61 @@
namespace Kernel { namespace Kernel {
pid_t Process::sys$getpid() KResultOr<pid_t> Process::sys$getpid()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return m_pid.value(); return m_pid.value();
} }
pid_t Process::sys$getppid() KResultOr<pid_t> Process::sys$getppid()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return m_ppid.value(); return m_ppid.value();
} }
int Process::sys$get_process_name(Userspace<char*> buffer, size_t buffer_size) KResultOr<int> Process::sys$get_process_name(Userspace<char*> buffer, size_t buffer_size)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (m_name.length() + 1 > buffer_size) if (m_name.length() + 1 > buffer_size)
return -ENAMETOOLONG; return ENAMETOOLONG;
if (!copy_to_user(buffer, m_name.characters(), m_name.length() + 1)) if (!copy_to_user(buffer, m_name.characters(), m_name.length() + 1))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$set_process_name(Userspace<const char*> user_name, size_t user_name_length) KResultOr<int> Process::sys$set_process_name(Userspace<const char*> user_name, size_t user_name_length)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
if (user_name_length > 256) if (user_name_length > 256)
return -ENAMETOOLONG; return ENAMETOOLONG;
auto name = copy_string_from_user(user_name, user_name_length); auto name = copy_string_from_user(user_name, user_name_length);
if (name.is_null()) if (name.is_null())
return -EFAULT; return EFAULT;
// Empty and whitespace-only names only exist to confuse users. // Empty and whitespace-only names only exist to confuse users.
if (name.is_whitespace()) if (name.is_whitespace())
return -EINVAL; return EINVAL;
m_name = move(name); m_name = move(name);
return 0; return 0;
} }
int Process::sys$set_coredump_metadata(Userspace<const Syscall::SC_set_coredump_metadata_params*> user_params) KResultOr<int> Process::sys$set_coredump_metadata(Userspace<const Syscall::SC_set_coredump_metadata_params*> user_params)
{ {
Syscall::SC_set_coredump_metadata_params params; Syscall::SC_set_coredump_metadata_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
if (params.key.length == 0 || params.key.length > 16 * KiB) if (params.key.length == 0 || params.key.length > 16 * KiB)
return -EINVAL; return EINVAL;
if (params.value.length > 16 * KiB) if (params.value.length > 16 * KiB)
return -EINVAL; return EINVAL;
auto copied_key = copy_string_from_user(params.key.characters, params.key.length); auto copied_key = copy_string_from_user(params.key.characters, params.key.length);
if (copied_key.is_null()) if (copied_key.is_null())
return -EFAULT; return EFAULT;
auto copied_value = copy_string_from_user(params.value.characters, params.value.length); auto copied_value = copy_string_from_user(params.value.characters, params.value.length);
if (copied_value.is_null()) if (copied_value.is_null())
return -EFAULT; return EFAULT;
if (!m_coredump_metadata.contains(copied_key) && m_coredump_metadata.size() >= 16) if (!m_coredump_metadata.contains(copied_key) && m_coredump_metadata.size() >= 16)
return -EFAULT; return EFAULT;
m_coredump_metadata.set(move(copied_key), move(copied_value)); m_coredump_metadata.set(move(copied_key), move(copied_value));
return 0; return 0;
} }

View file

@ -32,32 +32,32 @@
namespace Kernel { namespace Kernel {
int Process::sys$profiling_enable(pid_t pid) KResultOr<int> Process::sys$profiling_enable(pid_t pid)
{ {
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;
ScopedSpinLock lock(g_processes_lock); ScopedSpinLock lock(g_processes_lock);
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return -ESRCH; return ESRCH;
if (process->is_dead()) if (process->is_dead())
return -ESRCH; return ESRCH;
if (!is_superuser() && process->uid() != m_euid) if (!is_superuser() && process->uid() != m_euid)
return -EPERM; return EPERM;
process->ensure_perf_events(); process->ensure_perf_events();
process->set_profiling(true); process->set_profiling(true);
return 0; return 0;
} }
int Process::sys$profiling_disable(pid_t pid) KResultOr<int> Process::sys$profiling_disable(pid_t pid)
{ {
ScopedSpinLock lock(g_processes_lock); ScopedSpinLock lock(g_processes_lock);
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return -ESRCH; return ESRCH;
if (!is_superuser() && process->uid() != m_euid) if (!is_superuser() && process->uid() != m_euid)
return -EPERM; return EPERM;
if (!process->is_profiling()) if (!process->is_profiling())
return -EINVAL; return EINVAL;
process->set_profiling(false); process->set_profiling(false);
return 0; return 0;
} }

View file

@ -160,12 +160,12 @@ static KResultOr<u32> handle_ptrace(const Kernel::Syscall::SC_ptrace_params& par
return KSuccess; return KSuccess;
} }
int Process::sys$ptrace(Userspace<const Syscall::SC_ptrace_params*> user_params) KResultOr<int> Process::sys$ptrace(Userspace<const Syscall::SC_ptrace_params*> user_params)
{ {
REQUIRE_PROMISE(ptrace); REQUIRE_PROMISE(ptrace);
Syscall::SC_ptrace_params params {}; Syscall::SC_ptrace_params params {};
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto result = handle_ptrace(params, *this); auto result = handle_ptrace(params, *this);
return result.is_error() ? result.error().error() : result.value(); return result.is_error() ? result.error().error() : result.value();
} }

View file

@ -32,11 +32,11 @@
namespace Kernel { namespace Kernel {
int Process::sys$purge(int mode) KResultOr<int> Process::sys$purge(int mode)
{ {
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
int purged_page_count = 0; int purged_page_count = 0;
if (mode & PURGE_ALL_VOLATILE) { if (mode & PURGE_ALL_VOLATILE) {
NonnullRefPtrVector<AnonymousVMObject> vmobjects; NonnullRefPtrVector<AnonymousVMObject> vmobjects;

View file

@ -30,36 +30,36 @@
namespace Kernel { namespace Kernel {
ssize_t Process::sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count) KResultOr<ssize_t> Process::sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (iov_count < 0) if (iov_count < 0)
return -EINVAL; return EINVAL;
// Arbitrary pain threshold. // Arbitrary pain threshold.
if (iov_count > (int)MiB) if (iov_count > (int)MiB)
return -EFAULT; return EFAULT;
u64 total_length = 0; u64 total_length = 0;
Vector<iovec, 32> vecs; Vector<iovec, 32> vecs;
vecs.resize(iov_count); vecs.resize(iov_count);
if (!copy_n_from_user(vecs.data(), iov, iov_count)) if (!copy_n_from_user(vecs.data(), iov, iov_count))
return -EFAULT; return EFAULT;
for (auto& vec : vecs) { for (auto& vec : vecs) {
total_length += vec.iov_len; total_length += vec.iov_len;
if (total_length > NumericLimits<i32>::max()) if (total_length > NumericLimits<i32>::max())
return -EINVAL; return EINVAL;
} }
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_readable()) if (!description->is_readable())
return -EBADF; return EBADF;
if (description->is_directory()) if (description->is_directory())
return -EISDIR; return EISDIR;
int nread = 0; int nread = 0;
for (auto& vec : vecs) { for (auto& vec : vecs) {
@ -67,15 +67,15 @@ ssize_t Process::sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_c
if (!description->can_read()) { if (!description->can_read()) {
auto unblock_flags = Thread::FileBlocker::BlockFlags::None; auto unblock_flags = Thread::FileBlocker::BlockFlags::None;
if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted()) if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted())
return -EINTR; return EINTR;
if (!((u32)unblock_flags & (u32)Thread::FileBlocker::BlockFlags::Read)) if (!((u32)unblock_flags & (u32)Thread::FileBlocker::BlockFlags::Read))
return -EAGAIN; return EAGAIN;
// TODO: handle exceptions in unblock_flags // TODO: handle exceptions in unblock_flags
} }
} }
auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len); auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len);
if (!buffer.has_value()) if (!buffer.has_value())
return -EFAULT; return EFAULT;
auto result = description->read(buffer.value(), vec.iov_len); auto result = description->read(buffer.value(), vec.iov_len);
if (result.is_error()) if (result.is_error())
return result.error(); return result.error();
@ -85,34 +85,34 @@ ssize_t Process::sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_c
return nread; return nread;
} }
ssize_t Process::sys$read(int fd, Userspace<u8*> buffer, ssize_t size) KResultOr<ssize_t> Process::sys$read(int fd, Userspace<u8*> buffer, ssize_t size)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (size < 0) if (size < 0)
return -EINVAL; return EINVAL;
if (size == 0) if (size == 0)
return 0; return 0;
dbgln_if(IO_DEBUG, "sys$read({}, {}, {})", fd, buffer.ptr(), size); dbgln_if(IO_DEBUG, "sys$read({}, {}, {})", fd, buffer.ptr(), size);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_readable()) if (!description->is_readable())
return -EBADF; return EBADF;
if (description->is_directory()) if (description->is_directory())
return -EISDIR; return EISDIR;
if (description->is_blocking()) { if (description->is_blocking()) {
if (!description->can_read()) { if (!description->can_read()) {
auto unblock_flags = Thread::FileBlocker::BlockFlags::None; auto unblock_flags = Thread::FileBlocker::BlockFlags::None;
if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted()) if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted())
return -EINTR; return EINTR;
if (!((u32)unblock_flags & (u32)Thread::FileBlocker::BlockFlags::Read)) if (!((u32)unblock_flags & (u32)Thread::FileBlocker::BlockFlags::Read))
return -EAGAIN; return EAGAIN;
// TODO: handle exceptions in unblock_flags // TODO: handle exceptions in unblock_flags
} }
} }
auto user_buffer = UserOrKernelBuffer::for_user_buffer(buffer, size); auto user_buffer = UserOrKernelBuffer::for_user_buffer(buffer, size);
if (!user_buffer.has_value()) if (!user_buffer.has_value())
return -EFAULT; return EFAULT;
auto result = description->read(user_buffer.value(), size); auto result = description->read(user_buffer.value(), size);
if (result.is_error()) if (result.is_error())
return result.error(); return result.error();

View file

@ -31,13 +31,13 @@
namespace Kernel { namespace Kernel {
int Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_params) KResultOr<int> Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_params)
{ {
REQUIRE_PROMISE(rpath); REQUIRE_PROMISE(rpath);
Syscall::SC_readlink_params params; Syscall::SC_readlink_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto path = get_syscall_path_argument(params.path); auto path = get_syscall_path_argument(params.path);
if (path.is_error()) if (path.is_error())
@ -49,7 +49,7 @@ int Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_par
auto description = result.value(); auto description = result.value();
if (!description->metadata().is_symlink()) if (!description->metadata().is_symlink())
return -EINVAL; return EINVAL;
auto contents = description->read_entire_file(); auto contents = description->read_entire_file();
if (contents.is_error()) if (contents.is_error())
@ -58,7 +58,7 @@ int Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_par
auto& link_target = *contents.value(); auto& link_target = *contents.value();
auto size_to_copy = min(link_target.size(), params.buffer.size); auto size_to_copy = min(link_target.size(), params.buffer.size);
if (!copy_to_user(params.buffer.data, link_target.data(), size_to_copy)) if (!copy_to_user(params.buffer.data, link_target.data(), size_to_copy))
return -EFAULT; return EFAULT;
// Note: we return the whole size here, not the copied size. // Note: we return the whole size here, not the copied size.
return link_target.size(); return link_target.size();
} }

View file

@ -31,13 +31,13 @@
namespace Kernel { namespace Kernel {
int Process::sys$realpath(Userspace<const Syscall::SC_realpath_params*> user_params) KResultOr<int> Process::sys$realpath(Userspace<const Syscall::SC_realpath_params*> user_params)
{ {
REQUIRE_PROMISE(rpath); REQUIRE_PROMISE(rpath);
Syscall::SC_realpath_params params; Syscall::SC_realpath_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto path = get_syscall_path_argument(params.path); auto path = get_syscall_path_argument(params.path);
if (path.is_error()) if (path.is_error())
@ -52,7 +52,7 @@ int Process::sys$realpath(Userspace<const Syscall::SC_realpath_params*> user_par
size_t ideal_size = absolute_path.length() + 1; size_t ideal_size = absolute_path.length() + 1;
auto size_to_copy = min(ideal_size, params.buffer.size); auto size_to_copy = min(ideal_size, params.buffer.size);
if (!copy_to_user(params.buffer.data, absolute_path.characters(), size_to_copy)) if (!copy_to_user(params.buffer.data, absolute_path.characters(), size_to_copy))
return -EFAULT; return EFAULT;
// Note: we return the whole size here, not the copied size. // Note: we return the whole size here, not the copied size.
return ideal_size; return ideal_size;
}; };

View file

@ -30,12 +30,12 @@
namespace Kernel { namespace Kernel {
int Process::sys$rename(Userspace<const Syscall::SC_rename_params*> user_params) KResultOr<int> Process::sys$rename(Userspace<const Syscall::SC_rename_params*> user_params)
{ {
REQUIRE_PROMISE(cpath); REQUIRE_PROMISE(cpath);
Syscall::SC_rename_params params; Syscall::SC_rename_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto old_path = get_syscall_path_argument(params.old_path); auto old_path = get_syscall_path_argument(params.old_path);
if (old_path.is_error()) if (old_path.is_error())
return old_path.error(); return old_path.error();

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$rmdir(Userspace<const char*> user_path, size_t path_length) KResultOr<int> Process::sys$rmdir(Userspace<const char*> user_path, size_t path_length)
{ {
REQUIRE_PROMISE(cpath); REQUIRE_PROMISE(cpath);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);

View file

@ -28,36 +28,36 @@
namespace Kernel { namespace Kernel {
int Process::sys$yield() KResultOr<int> Process::sys$yield()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
Thread::current()->yield_without_holding_big_lock(); Thread::current()->yield_without_holding_big_lock();
return 0; return 0;
} }
int Process::sys$donate(pid_t tid) KResultOr<int> Process::sys$donate(pid_t tid)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (tid < 0) if (tid < 0)
return -EINVAL; return EINVAL;
ScopedCritical critical; ScopedCritical critical;
auto thread = Thread::from_tid(tid); auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid()) if (!thread || thread->pid() != pid())
return -ESRCH; return ESRCH;
Thread::current()->donate_without_holding_big_lock(thread, "sys$donate"); Thread::current()->donate_without_holding_big_lock(thread, "sys$donate");
return 0; return 0;
} }
int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> user_param) KResultOr<int> Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> user_param)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
struct sched_param desired_param; struct sched_param desired_param;
if (!copy_from_user(&desired_param, user_param)) if (!copy_from_user(&desired_param, user_param))
return -EFAULT; return EFAULT;
if (desired_param.sched_priority < THREAD_PRIORITY_MIN || desired_param.sched_priority > THREAD_PRIORITY_MAX) if (desired_param.sched_priority < THREAD_PRIORITY_MIN || desired_param.sched_priority > THREAD_PRIORITY_MAX)
return -EINVAL; return EINVAL;
auto* peer = Thread::current(); auto* peer = Thread::current();
ScopedSpinLock lock(g_scheduler_lock); ScopedSpinLock lock(g_scheduler_lock);
@ -65,16 +65,16 @@ int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> us
peer = Thread::from_tid(pid); peer = Thread::from_tid(pid);
if (!peer) if (!peer)
return -ESRCH; return ESRCH;
if (!is_superuser() && m_euid != peer->process().m_uid && m_uid != peer->process().m_uid) if (!is_superuser() && m_euid != peer->process().m_uid && m_uid != peer->process().m_uid)
return -EPERM; return EPERM;
peer->set_priority((u32)desired_param.sched_priority); peer->set_priority((u32)desired_param.sched_priority);
return 0; return 0;
} }
int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_param) KResultOr<int> Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_param)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
int priority; int priority;
@ -88,10 +88,10 @@ int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_p
} }
if (!peer) if (!peer)
return -ESRCH; return ESRCH;
if (!is_superuser() && m_euid != peer->process().m_uid && m_uid != peer->process().m_uid) if (!is_superuser() && m_euid != peer->process().m_uid && m_uid != peer->process().m_uid)
return -EPERM; return EPERM;
priority = (int)peer->priority(); priority = (int)peer->priority();
} }
@ -100,7 +100,7 @@ int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_p
priority priority
}; };
if (!copy_to_user(user_param, &param)) if (!copy_to_user(user_param, &param))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -32,22 +32,22 @@
namespace Kernel { namespace Kernel {
int Process::sys$select(const Syscall::SC_select_params* user_params) KResultOr<int> Process::sys$select(const Syscall::SC_select_params* user_params)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
Syscall::SC_select_params params; Syscall::SC_select_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
if (params.nfds < 0) if (params.nfds < 0)
return -EINVAL; return EINVAL;
Thread::BlockTimeout timeout; Thread::BlockTimeout timeout;
if (params.timeout) { if (params.timeout) {
timespec timeout_copy; timespec timeout_copy;
if (!copy_from_user(&timeout_copy, params.timeout)) if (!copy_from_user(&timeout_copy, params.timeout))
return -EFAULT; return EFAULT;
timeout = Thread::BlockTimeout(false, &timeout_copy); timeout = Thread::BlockTimeout(false, &timeout_copy);
} }
@ -57,7 +57,7 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
if (params.sigmask) { if (params.sigmask) {
sigset_t sigmask_copy; sigset_t sigmask_copy;
if (!copy_from_user(&sigmask_copy, params.sigmask)) if (!copy_from_user(&sigmask_copy, params.sigmask))
return -EFAULT; return EFAULT;
previous_signal_mask = current_thread->update_signal_mask(sigmask_copy); previous_signal_mask = current_thread->update_signal_mask(sigmask_copy);
} }
ScopeGuard rollback_signal_mask([&]() { ScopeGuard rollback_signal_mask([&]() {
@ -67,11 +67,11 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
fd_set fds_read, fds_write, fds_except; fd_set fds_read, fds_write, fds_except;
if (params.readfds && !copy_from_user(&fds_read, params.readfds)) if (params.readfds && !copy_from_user(&fds_read, params.readfds))
return -EFAULT; return EFAULT;
if (params.writefds && !copy_from_user(&fds_write, params.writefds)) if (params.writefds && !copy_from_user(&fds_write, params.writefds))
return -EFAULT; return EFAULT;
if (params.exceptfds && !copy_from_user(&fds_except, params.exceptfds)) if (params.exceptfds && !copy_from_user(&fds_except, params.exceptfds))
return -EFAULT; return EFAULT;
Thread::SelectBlocker::FDVector fds_info; Thread::SelectBlocker::FDVector fds_info;
Vector<int> fds; Vector<int> fds;
@ -89,7 +89,7 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
auto description = file_description(fd); auto description = file_description(fd);
if (!description) { if (!description) {
dbgln("sys$select: Bad fd number {}", fd); dbgln("sys$select: Bad fd number {}", fd);
return -EBADF; return EBADF;
} }
fds_info.append({ description.release_nonnull(), (Thread::FileBlocker::BlockFlags)block_flags }); fds_info.append({ description.release_nonnull(), (Thread::FileBlocker::BlockFlags)block_flags });
fds.append(fd); fds.append(fd);
@ -100,7 +100,7 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted()) { if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted()) {
dbgln_if(POLL_SELECT_DEBUG, "select was interrupted"); dbgln_if(POLL_SELECT_DEBUG, "select was interrupted");
return -EINTR; return EINTR;
} }
if (params.readfds) if (params.readfds)
@ -130,47 +130,47 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
} }
if (params.readfds && !copy_to_user(params.readfds, &fds_read)) if (params.readfds && !copy_to_user(params.readfds, &fds_read))
return -EFAULT; return EFAULT;
if (params.writefds && !copy_to_user(params.writefds, &fds_write)) if (params.writefds && !copy_to_user(params.writefds, &fds_write))
return -EFAULT; return EFAULT;
if (params.exceptfds && !copy_to_user(params.exceptfds, &fds_except)) if (params.exceptfds && !copy_to_user(params.exceptfds, &fds_except))
return -EFAULT; return EFAULT;
return marked_fd_count; return marked_fd_count;
} }
int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params) KResultOr<int> Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
// FIXME: Return -EINVAL if timeout is invalid. // FIXME: Return -EINVAL if timeout is invalid.
Syscall::SC_poll_params params; Syscall::SC_poll_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
if (params.nfds >= m_max_open_file_descriptors) if (params.nfds >= m_max_open_file_descriptors)
return -ENOBUFS; return ENOBUFS;
Thread::BlockTimeout timeout; Thread::BlockTimeout timeout;
if (params.timeout) { if (params.timeout) {
timespec timeout_copy; timespec timeout_copy;
if (!copy_from_user(&timeout_copy, params.timeout)) if (!copy_from_user(&timeout_copy, params.timeout))
return -EFAULT; return EFAULT;
timeout = Thread::BlockTimeout(false, &timeout_copy); timeout = Thread::BlockTimeout(false, &timeout_copy);
} }
sigset_t sigmask = {}; sigset_t sigmask = {};
if (params.sigmask && !copy_from_user(&sigmask, params.sigmask)) if (params.sigmask && !copy_from_user(&sigmask, params.sigmask))
return -EFAULT; return EFAULT;
Vector<pollfd> fds_copy; Vector<pollfd> fds_copy;
if (params.nfds > 0) { if (params.nfds > 0) {
Checked nfds_checked = sizeof(pollfd); Checked nfds_checked = sizeof(pollfd);
nfds_checked *= params.nfds; nfds_checked *= params.nfds;
if (nfds_checked.has_overflow()) if (nfds_checked.has_overflow())
return -EFAULT; return EFAULT;
fds_copy.resize(params.nfds); fds_copy.resize(params.nfds);
if (!copy_from_user(fds_copy.data(), &params.fds[0], nfds_checked.value())) if (!copy_from_user(fds_copy.data(), &params.fds[0], nfds_checked.value()))
return -EFAULT; return EFAULT;
} }
Thread::SelectBlocker::FDVector fds_info; Thread::SelectBlocker::FDVector fds_info;
@ -179,7 +179,7 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
auto description = file_description(pfd.fd); auto description = file_description(pfd.fd);
if (!description) { if (!description) {
dbgln("sys$poll: Bad fd number {}", pfd.fd); dbgln("sys$poll: Bad fd number {}", pfd.fd);
return -EBADF; return EBADF;
} }
u32 block_flags = (u32)Thread::FileBlocker::BlockFlags::Exception; // always want POLLERR, POLLHUP, POLLNVAL u32 block_flags = (u32)Thread::FileBlocker::BlockFlags::Exception; // always want POLLERR, POLLHUP, POLLNVAL
if (pfd.events & POLLIN) if (pfd.events & POLLIN)
@ -205,7 +205,7 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
dbgln("polling on {} fds, timeout={}", fds_info.size(), params.timeout); dbgln("polling on {} fds, timeout={}", fds_info.size(), params.timeout);
if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted()) if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted())
return -EINTR; return EINTR;
int fds_with_revents = 0; int fds_with_revents = 0;
@ -243,7 +243,7 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
} }
if (params.nfds > 0 && !copy_to_user(&params.fds[0], fds_copy.data(), params.nfds * sizeof(pollfd))) if (params.nfds > 0 && !copy_to_user(&params.fds[0], fds_copy.data(), params.nfds * sizeof(pollfd)))
return -EFAULT; return EFAULT;
return fds_with_revents; return fds_with_revents;
} }

View file

@ -30,39 +30,39 @@
namespace Kernel { namespace Kernel {
int Process::sys$sendfd(int sockfd, int fd) KResultOr<int> Process::sys$sendfd(int sockfd, int fd)
{ {
REQUIRE_PROMISE(sendfd); REQUIRE_PROMISE(sendfd);
auto socket_description = file_description(sockfd); auto socket_description = file_description(sockfd);
if (!socket_description) if (!socket_description)
return -EBADF; return EBADF;
if (!socket_description->is_socket()) if (!socket_description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *socket_description->socket(); auto& socket = *socket_description->socket();
if (!socket.is_local()) if (!socket.is_local())
return -EAFNOSUPPORT; return EAFNOSUPPORT;
if (!socket.is_connected()) if (!socket.is_connected())
return -ENOTCONN; return ENOTCONN;
auto passing_descriptor = file_description(fd); auto passing_descriptor = file_description(fd);
if (!passing_descriptor) if (!passing_descriptor)
return -EBADF; return EBADF;
auto& local_socket = static_cast<LocalSocket&>(socket); auto& local_socket = static_cast<LocalSocket&>(socket);
return local_socket.sendfd(*socket_description, *passing_descriptor); return local_socket.sendfd(*socket_description, *passing_descriptor);
} }
int Process::sys$recvfd(int sockfd, int options) KResultOr<int> Process::sys$recvfd(int sockfd, int options)
{ {
REQUIRE_PROMISE(recvfd); REQUIRE_PROMISE(recvfd);
auto socket_description = file_description(sockfd); auto socket_description = file_description(sockfd);
if (!socket_description) if (!socket_description)
return -EBADF; return EBADF;
if (!socket_description->is_socket()) if (!socket_description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *socket_description->socket(); auto& socket = *socket_description->socket();
if (!socket.is_local()) if (!socket.is_local())
return -EAFNOSUPPORT; return EAFNOSUPPORT;
int new_fd = alloc_fd(); int new_fd = alloc_fd();
if (new_fd < 0) if (new_fd < 0)

View file

@ -29,7 +29,7 @@
namespace Kernel { namespace Kernel {
pid_t Process::sys$getsid(pid_t pid) KResultOr<pid_t> Process::sys$getsid(pid_t pid)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
if (pid == 0) if (pid == 0)
@ -37,13 +37,13 @@ pid_t Process::sys$getsid(pid_t pid)
ScopedSpinLock lock(g_processes_lock); ScopedSpinLock lock(g_processes_lock);
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return -ESRCH; return ESRCH;
if (m_sid != process->m_sid) if (m_sid != process->m_sid)
return -EPERM; return EPERM;
return process->m_sid.value(); return process->m_sid.value();
} }
pid_t Process::sys$setsid() KResultOr<pid_t> Process::sys$setsid()
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
InterruptDisabler disabler; InterruptDisabler disabler;
@ -53,7 +53,7 @@ pid_t Process::sys$setsid()
return IterationDecision::Break; return IterationDecision::Break;
}); });
if (found_process_with_same_pgid_as_my_pid) if (found_process_with_same_pgid_as_my_pid)
return -EPERM; return EPERM;
// Create a new Session and a new ProcessGroup. // Create a new Session and a new ProcessGroup.
m_sid = m_pid.value(); m_sid = m_pid.value();
m_pg = ProcessGroup::create(ProcessGroupID(m_pid.value())); m_pg = ProcessGroup::create(ProcessGroupID(m_pid.value()));
@ -61,7 +61,7 @@ pid_t Process::sys$setsid()
return m_sid.value(); return m_sid.value();
} }
pid_t Process::sys$getpgid(pid_t pid) KResultOr<pid_t> Process::sys$getpgid(pid_t pid)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
if (pid == 0) if (pid == 0)
@ -69,11 +69,11 @@ pid_t Process::sys$getpgid(pid_t pid)
ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return -ESRCH; return ESRCH;
return process->pgid().value(); return process->pgid().value();
} }
pid_t Process::sys$getpgrp() KResultOr<pid_t> Process::sys$getpgrp()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return pgid().value(); return pgid().value();
@ -93,32 +93,32 @@ SessionID Process::get_sid_from_pgid(ProcessGroupID pgid)
return sid; return sid;
} }
int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid) KResultOr<int> Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle
ProcessID pid = specified_pid ? ProcessID(specified_pid) : m_pid; ProcessID pid = specified_pid ? ProcessID(specified_pid) : m_pid;
if (specified_pgid < 0) { if (specified_pgid < 0) {
// The value of the pgid argument is less than 0, or is not a value supported by the implementation. // The value of the pgid argument is less than 0, or is not a value supported by the implementation.
return -EINVAL; return EINVAL;
} }
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return -ESRCH; return ESRCH;
if (process != this && process->ppid() != m_pid) { if (process != this && process->ppid() != m_pid) {
// The value of the pid argument does not match the process ID // The value of the pid argument does not match the process ID
// of the calling process or of a child process of the calling process. // of the calling process or of a child process of the calling process.
return -ESRCH; return ESRCH;
} }
if (process->is_session_leader()) { if (process->is_session_leader()) {
// The process indicated by the pid argument is a session leader. // The process indicated by the pid argument is a session leader.
return -EPERM; return EPERM;
} }
if (process->ppid() == m_pid && process->sid() != sid()) { if (process->ppid() == m_pid && process->sid() != sid()) {
// The value of the pid argument matches the process ID of a child // The value of the pid argument matches the process ID of a child
// process of the calling process and the child process is not in // process of the calling process and the child process is not in
// the same session as the calling process. // the same session as the calling process.
return -EPERM; return EPERM;
} }
ProcessGroupID new_pgid = specified_pgid ? ProcessGroupID(specified_pgid) : process->m_pid.value(); ProcessGroupID new_pgid = specified_pgid ? ProcessGroupID(specified_pgid) : process->m_pid.value();
@ -126,12 +126,12 @@ int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
SessionID new_sid = get_sid_from_pgid(new_pgid); SessionID new_sid = get_sid_from_pgid(new_pgid);
if (new_sid != -1 && current_sid != new_sid) { if (new_sid != -1 && current_sid != new_sid) {
// Can't move a process between sessions. // Can't move a process between sessions.
return -EPERM; return EPERM;
} }
if (new_sid == -1 && new_pgid != process->m_pid.value()) { if (new_sid == -1 && new_pgid != process->m_pid.value()) {
// The value of the pgid argument is valid, but is not // The value of the pgid argument is valid, but is not
// the calling pid, and is not an existing process group. // the calling pid, and is not an existing process group.
return -EPERM; return EPERM;
} }
// FIXME: There are more EPERM conditions to check for here.. // FIXME: There are more EPERM conditions to check for here..
process->m_pg = ProcessGroup::find_or_create(new_pgid); process->m_pg = ProcessGroup::find_or_create(new_pgid);

View file

@ -28,12 +28,12 @@
namespace Kernel { namespace Kernel {
int Process::sys$seteuid(uid_t euid) KResultOr<int> Process::sys$seteuid(uid_t euid)
{ {
REQUIRE_PROMISE(id); REQUIRE_PROMISE(id);
if (euid != m_uid && euid != m_suid && !is_superuser()) if (euid != m_uid && euid != m_suid && !is_superuser())
return -EPERM; return EPERM;
if (m_euid != euid) if (m_euid != euid)
set_dumpable(false); set_dumpable(false);
@ -41,12 +41,12 @@ int Process::sys$seteuid(uid_t euid)
return 0; return 0;
} }
int Process::sys$setegid(gid_t egid) KResultOr<int> Process::sys$setegid(gid_t egid)
{ {
REQUIRE_PROMISE(id); REQUIRE_PROMISE(id);
if (egid != m_gid && egid != m_sgid && !is_superuser()) if (egid != m_gid && egid != m_sgid && !is_superuser())
return -EPERM; return EPERM;
if (m_egid != egid) if (m_egid != egid)
set_dumpable(false); set_dumpable(false);
@ -55,12 +55,12 @@ int Process::sys$setegid(gid_t egid)
return 0; return 0;
} }
int Process::sys$setuid(uid_t uid) KResultOr<int> Process::sys$setuid(uid_t uid)
{ {
REQUIRE_PROMISE(id); REQUIRE_PROMISE(id);
if (uid != m_uid && uid != m_euid && !is_superuser()) if (uid != m_uid && uid != m_euid && !is_superuser())
return -EPERM; return EPERM;
if (m_euid != uid) if (m_euid != uid)
set_dumpable(false); set_dumpable(false);
@ -71,12 +71,12 @@ int Process::sys$setuid(uid_t uid)
return 0; return 0;
} }
int Process::sys$setgid(gid_t gid) KResultOr<int> Process::sys$setgid(gid_t gid)
{ {
REQUIRE_PROMISE(id); REQUIRE_PROMISE(id);
if (gid != m_gid && gid != m_egid && !is_superuser()) if (gid != m_gid && gid != m_egid && !is_superuser())
return -EPERM; return EPERM;
if (m_egid != gid) if (m_egid != gid)
set_dumpable(false); set_dumpable(false);
@ -87,7 +87,7 @@ int Process::sys$setgid(gid_t gid)
return 0; return 0;
} }
int Process::sys$setresuid(uid_t ruid, uid_t euid, uid_t suid) KResultOr<int> Process::sys$setresuid(uid_t ruid, uid_t euid, uid_t suid)
{ {
REQUIRE_PROMISE(id); REQUIRE_PROMISE(id);
@ -100,7 +100,7 @@ int Process::sys$setresuid(uid_t ruid, uid_t euid, uid_t suid)
auto ok = [this](uid_t id) { return id == m_uid || id == m_euid || id == m_suid; }; auto ok = [this](uid_t id) { return id == m_uid || id == m_euid || id == m_suid; };
if ((!ok(ruid) || !ok(euid) || !ok(suid)) && !is_superuser()) if ((!ok(ruid) || !ok(euid) || !ok(suid)) && !is_superuser())
return -EPERM; return EPERM;
if (m_euid != euid) if (m_euid != euid)
set_dumpable(false); set_dumpable(false);
@ -111,7 +111,7 @@ int Process::sys$setresuid(uid_t ruid, uid_t euid, uid_t suid)
return 0; return 0;
} }
int Process::sys$setresgid(gid_t rgid, gid_t egid, gid_t sgid) KResultOr<int> Process::sys$setresgid(gid_t rgid, gid_t egid, gid_t sgid)
{ {
REQUIRE_PROMISE(id); REQUIRE_PROMISE(id);
@ -124,7 +124,7 @@ int Process::sys$setresgid(gid_t rgid, gid_t egid, gid_t sgid)
auto ok = [this](gid_t id) { return id == m_gid || id == m_egid || id == m_sgid; }; auto ok = [this](gid_t id) { return id == m_gid || id == m_egid || id == m_sgid; };
if ((!ok(rgid) || !ok(egid) || !ok(sgid)) && !is_superuser()) if ((!ok(rgid) || !ok(egid) || !ok(sgid)) && !is_superuser())
return -EPERM; return EPERM;
if (m_egid != egid) if (m_egid != egid)
set_dumpable(false); set_dumpable(false);
@ -135,13 +135,13 @@ int Process::sys$setresgid(gid_t rgid, gid_t egid, gid_t sgid)
return 0; return 0;
} }
int Process::sys$setgroups(ssize_t count, Userspace<const gid_t*> user_gids) KResultOr<int> Process::sys$setgroups(ssize_t count, Userspace<const gid_t*> user_gids)
{ {
REQUIRE_PROMISE(id); REQUIRE_PROMISE(id);
if (count < 0) if (count < 0)
return -EINVAL; return EINVAL;
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
if (!count) { if (!count) {
m_extra_gids.clear(); m_extra_gids.clear();
@ -151,7 +151,7 @@ int Process::sys$setgroups(ssize_t count, Userspace<const gid_t*> user_gids)
Vector<gid_t> gids; Vector<gid_t> gids;
gids.resize(count); gids.resize(count);
if (!copy_n_from_user(gids.data(), user_gids, count)) if (!copy_n_from_user(gids.data(), user_gids, count))
return -EFAULT; return EFAULT;
HashTable<gid_t> unique_extra_gids; HashTable<gid_t> unique_extra_gids;
for (auto& gid : gids) { for (auto& gid : gids) {

View file

@ -31,10 +31,10 @@
namespace Kernel { namespace Kernel {
int Process::sys$reboot() KResultOr<int> Process::sys$reboot()
{ {
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;
@ -51,10 +51,10 @@ int Process::sys$reboot()
return 0; return 0;
} }
int Process::sys$halt() KResultOr<int> Process::sys$halt()
{ {
if (!is_superuser()) if (!is_superuser())
return -EPERM; return EPERM;
REQUIRE_NO_PROMISES; REQUIRE_NO_PROMISES;

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<sigset_t*> old_set) KResultOr<int> Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<sigset_t*> old_set)
{ {
REQUIRE_PROMISE(sigaction); REQUIRE_PROMISE(sigaction);
auto current_thread = Thread::current(); auto current_thread = Thread::current();
@ -38,7 +38,7 @@ int Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<
if (set) { if (set) {
sigset_t set_value; sigset_t set_value;
if (!copy_from_user(&set_value, set)) if (!copy_from_user(&set_value, set))
return -EFAULT; return EFAULT;
switch (how) { switch (how) {
case SIG_BLOCK: case SIG_BLOCK:
previous_signal_mask = current_thread->signal_mask_block(set_value, true); previous_signal_mask = current_thread->signal_mask_block(set_value, true);
@ -50,46 +50,46 @@ int Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<
previous_signal_mask = current_thread->update_signal_mask(set_value); previous_signal_mask = current_thread->update_signal_mask(set_value);
break; break;
default: default:
return -EINVAL; return EINVAL;
} }
} else { } else {
previous_signal_mask = current_thread->signal_mask(); previous_signal_mask = current_thread->signal_mask();
} }
if (old_set && !copy_to_user(old_set, &previous_signal_mask)) if (old_set && !copy_to_user(old_set, &previous_signal_mask))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$sigpending(Userspace<sigset_t*> set) KResultOr<int> Process::sys$sigpending(Userspace<sigset_t*> set)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto pending_signals = Thread::current()->pending_signals(); auto pending_signals = Thread::current()->pending_signals();
if (!copy_to_user(set, &pending_signals)) if (!copy_to_user(set, &pending_signals))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act) KResultOr<int> Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act)
{ {
REQUIRE_PROMISE(sigaction); REQUIRE_PROMISE(sigaction);
if (signum < 1 || signum >= 32 || signum == SIGKILL || signum == SIGSTOP) if (signum < 1 || signum >= 32 || signum == SIGKILL || signum == SIGSTOP)
return -EINVAL; return EINVAL;
InterruptDisabler disabler; // FIXME: This should use a narrower lock. Maybe a way to ignore signals temporarily? InterruptDisabler disabler; // FIXME: This should use a narrower lock. Maybe a way to ignore signals temporarily?
auto& action = Thread::current()->m_signal_action_data[signum]; auto& action = Thread::current()->m_signal_action_data[signum];
if (old_act) { if (old_act) {
if (!copy_to_user(&old_act->sa_flags, &action.flags)) if (!copy_to_user(&old_act->sa_flags, &action.flags))
return -EFAULT; return EFAULT;
if (!copy_to_user(&old_act->sa_sigaction, &action.handler_or_sigaction, sizeof(action.handler_or_sigaction))) if (!copy_to_user(&old_act->sa_sigaction, &action.handler_or_sigaction, sizeof(action.handler_or_sigaction)))
return -EFAULT; return EFAULT;
} }
if (!copy_from_user(&action.flags, &act->sa_flags)) if (!copy_from_user(&action.flags, &act->sa_flags))
return -EFAULT; return EFAULT;
if (!copy_from_user(&action.handler_or_sigaction, &act->sa_sigaction, sizeof(action.handler_or_sigaction))) if (!copy_from_user(&action.handler_or_sigaction, &act->sa_sigaction, sizeof(action.handler_or_sigaction)))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$sigreturn([[maybe_unused]] RegisterState& registers) KResultOr<int> Process::sys$sigreturn([[maybe_unused]] RegisterState& registers)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
SmapDisabler disabler; SmapDisabler disabler;

View file

@ -40,12 +40,12 @@ namespace Kernel {
REQUIRE_PROMISE(unix); \ REQUIRE_PROMISE(unix); \
} while (0) } while (0)
int Process::sys$socket(int domain, int type, int protocol) KResultOr<int> Process::sys$socket(int domain, int type, int protocol)
{ {
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain); REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain);
if ((type & SOCK_TYPE_MASK) == SOCK_RAW && !is_superuser()) if ((type & SOCK_TYPE_MASK) == SOCK_RAW && !is_superuser())
return -EACCES; return EACCES;
int fd = alloc_fd(); int fd = alloc_fd();
if (fd < 0) if (fd < 0)
return fd; return fd;
@ -66,59 +66,59 @@ int Process::sys$socket(int domain, int type, int protocol)
return fd; return fd;
} }
int Process::sys$bind(int sockfd, Userspace<const sockaddr*> address, socklen_t address_length) KResultOr<int> Process::sys$bind(int sockfd, Userspace<const sockaddr*> address, socklen_t address_length)
{ {
auto description = file_description(sockfd); auto description = file_description(sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
return socket.bind(address, address_length); return socket.bind(address, address_length);
} }
int Process::sys$listen(int sockfd, int backlog) KResultOr<int> Process::sys$listen(int sockfd, int backlog)
{ {
if (backlog < 0) if (backlog < 0)
return -EINVAL; return EINVAL;
auto description = file_description(sockfd); auto description = file_description(sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
if (socket.is_connected()) if (socket.is_connected())
return -EINVAL; return EINVAL;
return socket.listen(backlog); return socket.listen(backlog);
} }
int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_address, Userspace<socklen_t*> user_address_size) KResultOr<int> Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_address, Userspace<socklen_t*> user_address_size)
{ {
REQUIRE_PROMISE(accept); REQUIRE_PROMISE(accept);
socklen_t address_size = 0; socklen_t address_size = 0;
if (user_address && !copy_from_user(&address_size, static_ptr_cast<const socklen_t*>(user_address_size))) if (user_address && !copy_from_user(&address_size, static_ptr_cast<const socklen_t*>(user_address_size)))
return -EFAULT; return EFAULT;
int accepted_socket_fd = alloc_fd(); int accepted_socket_fd = alloc_fd();
if (accepted_socket_fd < 0) if (accepted_socket_fd < 0)
return accepted_socket_fd; return accepted_socket_fd;
auto accepting_socket_description = file_description(accepting_socket_fd); auto accepting_socket_description = file_description(accepting_socket_fd);
if (!accepting_socket_description) if (!accepting_socket_description)
return -EBADF; return EBADF;
if (!accepting_socket_description->is_socket()) if (!accepting_socket_description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *accepting_socket_description->socket(); auto& socket = *accepting_socket_description->socket();
if (!socket.can_accept()) { if (!socket.can_accept()) {
if (accepting_socket_description->is_blocking()) { if (accepting_socket_description->is_blocking()) {
auto unblock_flags = Thread::FileBlocker::BlockFlags::None; auto unblock_flags = Thread::FileBlocker::BlockFlags::None;
if (Thread::current()->block<Thread::AcceptBlocker>({}, *accepting_socket_description, unblock_flags).was_interrupted()) if (Thread::current()->block<Thread::AcceptBlocker>({}, *accepting_socket_description, unblock_flags).was_interrupted())
return -EINTR; return EINTR;
} else { } else {
return -EAGAIN; return EAGAIN;
} }
} }
auto accepted_socket = socket.accept(); auto accepted_socket = socket.accept();
@ -129,9 +129,9 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
address_size = min(sizeof(sockaddr_un), static_cast<size_t>(address_size)); address_size = min(sizeof(sockaddr_un), static_cast<size_t>(address_size));
accepted_socket->get_peer_address((sockaddr*)address_buffer, &address_size); accepted_socket->get_peer_address((sockaddr*)address_buffer, &address_size);
if (!copy_to_user(user_address, address_buffer, address_size)) if (!copy_to_user(user_address, address_buffer, address_size))
return -EFAULT; return EFAULT;
if (!copy_to_user(user_address_size, &address_size)) if (!copy_to_user(user_address_size, &address_size))
return -EFAULT; return EFAULT;
} }
auto accepted_socket_description_result = FileDescription::create(*accepted_socket); auto accepted_socket_description_result = FileDescription::create(*accepted_socket);
@ -150,16 +150,16 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
return accepted_socket_fd; return accepted_socket_fd;
} }
int Process::sys$connect(int sockfd, Userspace<const sockaddr*> user_address, socklen_t user_address_size) KResultOr<int> Process::sys$connect(int sockfd, Userspace<const sockaddr*> user_address, socklen_t user_address_size)
{ {
int fd = alloc_fd(); int fd = alloc_fd();
if (fd < 0) if (fd < 0)
return fd; return fd;
auto description = file_description(sockfd); auto description = file_description(sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
@ -167,79 +167,79 @@ int Process::sys$connect(int sockfd, Userspace<const sockaddr*> user_address, so
return socket.connect(*description, user_address, user_address_size, description->is_blocking() ? ShouldBlock::Yes : ShouldBlock::No); return socket.connect(*description, user_address, user_address_size, description->is_blocking() ? ShouldBlock::Yes : ShouldBlock::No);
} }
int Process::sys$shutdown(int sockfd, int how) KResultOr<int> Process::sys$shutdown(int sockfd, int how)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (how & ~SHUT_RDWR) if (how & ~SHUT_RDWR)
return -EINVAL; return EINVAL;
auto description = file_description(sockfd); auto description = file_description(sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
return socket.shutdown(how); return socket.shutdown(how);
} }
ssize_t Process::sys$sendmsg(int sockfd, Userspace<const struct msghdr*> user_msg, int flags) KResultOr<ssize_t> Process::sys$sendmsg(int sockfd, Userspace<const struct msghdr*> user_msg, int flags)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
struct msghdr msg; struct msghdr msg;
if (!copy_from_user(&msg, user_msg)) if (!copy_from_user(&msg, user_msg))
return -EFAULT; return EFAULT;
if (msg.msg_iovlen != 1) if (msg.msg_iovlen != 1)
return -ENOTSUP; // FIXME: Support this :) return ENOTSUP; // FIXME: Support this :)
Vector<iovec, 1> iovs; Vector<iovec, 1> iovs;
iovs.resize(msg.msg_iovlen); iovs.resize(msg.msg_iovlen);
if (!copy_n_from_user(iovs.data(), msg.msg_iov, msg.msg_iovlen)) if (!copy_n_from_user(iovs.data(), msg.msg_iov, msg.msg_iovlen))
return -EFAULT; return EFAULT;
Userspace<const sockaddr*> user_addr((FlatPtr)msg.msg_name); Userspace<const sockaddr*> user_addr((FlatPtr)msg.msg_name);
socklen_t addr_length = msg.msg_namelen; socklen_t addr_length = msg.msg_namelen;
auto description = file_description(sockfd); auto description = file_description(sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
if (socket.is_shut_down_for_writing()) if (socket.is_shut_down_for_writing())
return -EPIPE; return EPIPE;
auto data_buffer = UserOrKernelBuffer::for_user_buffer((u8*)iovs[0].iov_base, iovs[0].iov_len); auto data_buffer = UserOrKernelBuffer::for_user_buffer((u8*)iovs[0].iov_base, iovs[0].iov_len);
if (!data_buffer.has_value()) if (!data_buffer.has_value())
return -EFAULT; return EFAULT;
auto result = socket.sendto(*description, data_buffer.value(), iovs[0].iov_len, flags, user_addr, addr_length); auto result = socket.sendto(*description, data_buffer.value(), iovs[0].iov_len, flags, user_addr, addr_length);
if (result.is_error()) if (result.is_error())
return result.error(); return result.error();
return result.value(); return result.value();
} }
ssize_t Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user_msg, int flags) KResultOr<ssize_t> Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user_msg, int flags)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
struct msghdr msg; struct msghdr msg;
if (!copy_from_user(&msg, user_msg)) if (!copy_from_user(&msg, user_msg))
return -EFAULT; return EFAULT;
if (msg.msg_iovlen != 1) if (msg.msg_iovlen != 1)
return -ENOTSUP; // FIXME: Support this :) return ENOTSUP; // FIXME: Support this :)
Vector<iovec, 1> iovs; Vector<iovec, 1> iovs;
iovs.resize(msg.msg_iovlen); iovs.resize(msg.msg_iovlen);
if (!copy_n_from_user(iovs.data(), msg.msg_iov, msg.msg_iovlen)) if (!copy_n_from_user(iovs.data(), msg.msg_iov, msg.msg_iovlen))
return -EFAULT; return EFAULT;
Userspace<sockaddr*> user_addr((FlatPtr)msg.msg_name); Userspace<sockaddr*> user_addr((FlatPtr)msg.msg_name);
Userspace<socklen_t*> user_addr_length(msg.msg_name ? (FlatPtr)&user_msg.unsafe_userspace_ptr()->msg_namelen : 0); Userspace<socklen_t*> user_addr_length(msg.msg_name ? (FlatPtr)&user_msg.unsafe_userspace_ptr()->msg_namelen : 0);
auto description = file_description(sockfd); auto description = file_description(sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
if (socket.is_shut_down_for_reading()) if (socket.is_shut_down_for_reading())
@ -251,7 +251,7 @@ ssize_t Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user_msg, int
auto data_buffer = UserOrKernelBuffer::for_user_buffer((u8*)iovs[0].iov_base, iovs[0].iov_len); auto data_buffer = UserOrKernelBuffer::for_user_buffer((u8*)iovs[0].iov_base, iovs[0].iov_len);
if (!data_buffer.has_value()) if (!data_buffer.has_value())
return -EFAULT; return EFAULT;
timeval timestamp = { 0, 0 }; timeval timestamp = { 0, 0 };
auto result = socket.recvfrom(*description, data_buffer.value(), iovs[0].iov_len, flags, user_addr, user_addr_length, timestamp); auto result = socket.recvfrom(*description, data_buffer.value(), iovs[0].iov_len, flags, user_addr, user_addr_length, timestamp);
if (flags & MSG_DONTWAIT) if (flags & MSG_DONTWAIT)
@ -278,14 +278,14 @@ ssize_t Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user_msg, int
} else { } else {
cmsg_timestamp = { { control_length, SOL_SOCKET, SCM_TIMESTAMP }, timestamp }; cmsg_timestamp = { { control_length, SOL_SOCKET, SCM_TIMESTAMP }, timestamp };
if (!copy_to_user(msg.msg_control, &cmsg_timestamp, control_length)) if (!copy_to_user(msg.msg_control, &cmsg_timestamp, control_length))
return -EFAULT; return EFAULT;
} }
if (!copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_controllen, &control_length)) if (!copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_controllen, &control_length))
return -EFAULT; return EFAULT;
} }
if (!copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_flags, &msg_flags)) if (!copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_flags, &msg_flags))
return -EFAULT; return EFAULT;
return result.value(); return result.value();
} }
@ -295,17 +295,17 @@ int Process::get_sock_or_peer_name(const Params& params)
{ {
socklen_t addrlen_value; socklen_t addrlen_value;
if (!copy_from_user(&addrlen_value, params.addrlen, sizeof(socklen_t))) if (!copy_from_user(&addrlen_value, params.addrlen, sizeof(socklen_t)))
return -EFAULT; return EFAULT;
if (addrlen_value <= 0) if (addrlen_value <= 0)
return -EINVAL; return EINVAL;
auto description = file_description(params.sockfd); auto description = file_description(params.sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
@ -317,33 +317,33 @@ int Process::get_sock_or_peer_name(const Params& params)
else else
socket.get_peer_address((sockaddr*)address_buffer, &addrlen_value); socket.get_peer_address((sockaddr*)address_buffer, &addrlen_value);
if (!copy_to_user(params.addr, address_buffer, addrlen_value)) if (!copy_to_user(params.addr, address_buffer, addrlen_value))
return -EFAULT; return EFAULT;
if (!copy_to_user(params.addrlen, &addrlen_value)) if (!copy_to_user(params.addrlen, &addrlen_value))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$getsockname(Userspace<const Syscall::SC_getsockname_params*> user_params) KResultOr<int> Process::sys$getsockname(Userspace<const Syscall::SC_getsockname_params*> user_params)
{ {
Syscall::SC_getsockname_params params; Syscall::SC_getsockname_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
return get_sock_or_peer_name<true>(params); return get_sock_or_peer_name<true>(params);
} }
int Process::sys$getpeername(Userspace<const Syscall::SC_getpeername_params*> user_params) KResultOr<int> Process::sys$getpeername(Userspace<const Syscall::SC_getpeername_params*> user_params)
{ {
Syscall::SC_getpeername_params params; Syscall::SC_getpeername_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
return get_sock_or_peer_name<false>(params); return get_sock_or_peer_name<false>(params);
} }
int Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user_params) KResultOr<int> Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user_params)
{ {
Syscall::SC_getsockopt_params params; Syscall::SC_getsockopt_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
int sockfd = params.sockfd; int sockfd = params.sockfd;
int level = params.level; int level = params.level;
@ -353,30 +353,30 @@ int Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user
socklen_t value_size; socklen_t value_size;
if (!copy_from_user(&value_size, params.value_size, sizeof(socklen_t))) if (!copy_from_user(&value_size, params.value_size, sizeof(socklen_t)))
return -EFAULT; return EFAULT;
auto description = file_description(sockfd); auto description = file_description(sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
return socket.getsockopt(*description, level, option, user_value, user_value_size); return socket.getsockopt(*description, level, option, user_value, user_value_size);
} }
int Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*> user_params) KResultOr<int> Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*> user_params)
{ {
Syscall::SC_setsockopt_params params; Syscall::SC_setsockopt_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
Userspace<const void*> user_value((FlatPtr)params.value); Userspace<const void*> user_value((FlatPtr)params.value);
auto description = file_description(params.sockfd); auto description = file_description(params.sockfd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_socket()) if (!description->is_socket())
return -ENOTSOCK; return ENOTSOCK;
auto& socket = *description->socket(); auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain()); REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
return socket.setsockopt(params.level, params.option, user_value, params.value_size); return socket.setsockopt(params.level, params.option, user_value, params.value_size);

View file

@ -31,25 +31,25 @@
namespace Kernel { namespace Kernel {
int Process::sys$fstat(int fd, Userspace<stat*> user_statbuf) KResultOr<int> Process::sys$fstat(int fd, Userspace<stat*> user_statbuf)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
stat buffer = {}; stat buffer = {};
int rc = description->stat(buffer); int rc = description->stat(buffer);
if (!copy_to_user(user_statbuf, &buffer)) if (!copy_to_user(user_statbuf, &buffer))
return -EFAULT; return EFAULT;
return rc; return rc;
} }
int Process::sys$stat(Userspace<const Syscall::SC_stat_params*> user_params) KResultOr<int> Process::sys$stat(Userspace<const Syscall::SC_stat_params*> user_params)
{ {
REQUIRE_PROMISE(rpath); REQUIRE_PROMISE(rpath);
Syscall::SC_stat_params params; Syscall::SC_stat_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
auto path = get_syscall_path_argument(params.path); auto path = get_syscall_path_argument(params.path);
if (path.is_error()) if (path.is_error())
return path.error(); return path.error();
@ -61,7 +61,7 @@ int Process::sys$stat(Userspace<const Syscall::SC_stat_params*> user_params)
if (result.is_error()) if (result.is_error())
return result; return result;
if (!copy_to_user(params.statbuf, &statbuf)) if (!copy_to_user(params.statbuf, &statbuf))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -29,7 +29,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$sync() KResultOr<int> Process::sys$sync()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
VFS::the().sync(); VFS::the().sync();

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
long Process::sys$sysconf(int name) KResultOr<long> Process::sys$sysconf(int name)
{ {
switch (name) { switch (name) {
case _SC_NPROCESSORS_CONF: case _SC_NPROCESSORS_CONF:
@ -45,7 +45,7 @@ long Process::sys$sysconf(int name)
case _SC_GETPW_R_SIZE_MAX: case _SC_GETPW_R_SIZE_MAX:
return 4096; // idk return 4096; // idk
default: default:
return -EINVAL; return EINVAL;
} }
} }

View file

@ -34,31 +34,31 @@
namespace Kernel { namespace Kernel {
int Process::sys$create_thread(void* (*entry)(void*), Userspace<const Syscall::SC_create_thread_params*> user_params) KResultOr<int> Process::sys$create_thread(void* (*entry)(void*), Userspace<const Syscall::SC_create_thread_params*> user_params)
{ {
REQUIRE_PROMISE(thread); REQUIRE_PROMISE(thread);
Syscall::SC_create_thread_params params; Syscall::SC_create_thread_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
unsigned detach_state = params.m_detach_state; unsigned detach_state = params.m_detach_state;
int schedule_priority = params.m_schedule_priority; int schedule_priority = params.m_schedule_priority;
unsigned stack_size = params.m_stack_size; unsigned stack_size = params.m_stack_size;
if (Checked<FlatPtr>::addition_would_overflow((FlatPtr)params.m_stack_location, stack_size)) if (Checked<FlatPtr>::addition_would_overflow((FlatPtr)params.m_stack_location, stack_size))
return -EOVERFLOW; return EOVERFLOW;
auto user_stack_address = (u8*)params.m_stack_location + stack_size; auto user_stack_address = (u8*)params.m_stack_location + stack_size;
if (!MM.validate_user_stack(*this, VirtualAddress(user_stack_address - 4))) if (!MM.validate_user_stack(*this, VirtualAddress(user_stack_address - 4)))
return -EFAULT; return EFAULT;
// FIXME: return EAGAIN if Thread::all_threads().size() is greater than PTHREAD_THREADS_MAX // FIXME: return EAGAIN if Thread::all_threads().size() is greater than PTHREAD_THREADS_MAX
int requested_thread_priority = schedule_priority; int requested_thread_priority = schedule_priority;
if (requested_thread_priority < THREAD_PRIORITY_MIN || requested_thread_priority > THREAD_PRIORITY_MAX) if (requested_thread_priority < THREAD_PRIORITY_MIN || requested_thread_priority > THREAD_PRIORITY_MAX)
return -EINVAL; return EINVAL;
bool is_thread_joinable = (0 == detach_state); bool is_thread_joinable = (0 == detach_state);
@ -108,31 +108,31 @@ void Process::sys$exit_thread(Userspace<void*> exit_value)
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
int Process::sys$detach_thread(pid_t tid) KResultOr<int> Process::sys$detach_thread(pid_t tid)
{ {
REQUIRE_PROMISE(thread); REQUIRE_PROMISE(thread);
auto thread = Thread::from_tid(tid); auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid()) if (!thread || thread->pid() != pid())
return -ESRCH; return ESRCH;
if (!thread->is_joinable()) if (!thread->is_joinable())
return -EINVAL; return EINVAL;
thread->detach(); thread->detach();
return 0; return 0;
} }
int Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value) KResultOr<int> Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value)
{ {
REQUIRE_PROMISE(thread); REQUIRE_PROMISE(thread);
auto thread = Thread::from_tid(tid); auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid()) if (!thread || thread->pid() != pid())
return -ESRCH; return ESRCH;
auto current_thread = Thread::current(); auto current_thread = Thread::current();
if (thread == current_thread) if (thread == current_thread)
return -EDEADLK; return EDEADLK;
void* joinee_exit_value = nullptr; void* joinee_exit_value = nullptr;
@ -151,50 +151,50 @@ int Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value)
} }
if (exit_value && !copy_to_user(exit_value, &joinee_exit_value)) if (exit_value && !copy_to_user(exit_value, &joinee_exit_value))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$set_thread_name(pid_t tid, Userspace<const char*> user_name, size_t user_name_length) KResultOr<int> Process::sys$set_thread_name(pid_t tid, Userspace<const char*> user_name, size_t user_name_length)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto name = copy_string_from_user(user_name, user_name_length); auto name = copy_string_from_user(user_name, user_name_length);
if (name.is_null()) if (name.is_null())
return -EFAULT; return EFAULT;
const size_t max_thread_name_size = 64; const size_t max_thread_name_size = 64;
if (name.length() > max_thread_name_size) if (name.length() > max_thread_name_size)
return -EINVAL; return EINVAL;
auto thread = Thread::from_tid(tid); auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid()) if (!thread || thread->pid() != pid())
return -ESRCH; return ESRCH;
thread->set_name(move(name)); thread->set_name(move(name));
return 0; return 0;
} }
int Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buffer_size) KResultOr<int> Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buffer_size)
{ {
REQUIRE_PROMISE(thread); REQUIRE_PROMISE(thread);
if (buffer_size == 0) if (buffer_size == 0)
return -EINVAL; return EINVAL;
auto thread = Thread::from_tid(tid); auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid()) if (!thread || thread->pid() != pid())
return -ESRCH; return ESRCH;
// We must make a temporary copy here to avoid a race with sys$set_thread_name // We must make a temporary copy here to avoid a race with sys$set_thread_name
auto thread_name = thread->name(); auto thread_name = thread->name();
if (thread_name.length() + 1 > (size_t)buffer_size) if (thread_name.length() + 1 > (size_t)buffer_size)
return -ENAMETOOLONG; return ENAMETOOLONG;
if (!copy_to_user(buffer, thread_name.characters(), thread_name.length() + 1)) if (!copy_to_user(buffer, thread_name.characters(), thread_name.length() + 1))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$gettid() KResultOr<int> Process::sys$gettid()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return Thread::current()->tid().value(); return Thread::current()->tid().value();

View file

@ -28,7 +28,7 @@
namespace Kernel { namespace Kernel {
clock_t Process::sys$times(Userspace<tms*> user_times) KResultOr<clock_t> Process::sys$times(Userspace<tms*> user_times)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
tms times = {}; tms times = {};
@ -38,7 +38,7 @@ clock_t Process::sys$times(Userspace<tms*> user_times)
times.tms_cstime = m_ticks_in_kernel_for_dead_children; times.tms_cstime = m_ticks_in_kernel_for_dead_children;
if (!copy_to_user(user_times, &times)) if (!copy_to_user(user_times, &times))
return -EFAULT; return EFAULT;
return TimeManagement::the().uptime_ms() & 0x7fffffff; return TimeManagement::the().uptime_ms() & 0x7fffffff;
} }

View file

@ -31,36 +31,36 @@
namespace Kernel { namespace Kernel {
int Process::sys$ttyname(int fd, Userspace<char*> buffer, size_t size) KResultOr<int> Process::sys$ttyname(int fd, Userspace<char*> buffer, size_t size)
{ {
REQUIRE_PROMISE(tty); REQUIRE_PROMISE(tty);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_tty()) if (!description->is_tty())
return -ENOTTY; return ENOTTY;
auto tty_name = description->tty()->tty_name(); auto tty_name = description->tty()->tty_name();
if (size < tty_name.length() + 1) if (size < tty_name.length() + 1)
return -ERANGE; return ERANGE;
if (!copy_to_user(buffer, tty_name.characters(), tty_name.length() + 1)) if (!copy_to_user(buffer, tty_name.characters(), tty_name.length() + 1))
return -EFAULT; return EFAULT;
return 0; return 0;
} }
int Process::sys$ptsname(int fd, Userspace<char*> buffer, size_t size) KResultOr<int> Process::sys$ptsname(int fd, Userspace<char*> buffer, size_t size)
{ {
REQUIRE_PROMISE(tty); REQUIRE_PROMISE(tty);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
auto* master_pty = description->master_pty(); auto* master_pty = description->master_pty();
if (!master_pty) if (!master_pty)
return -ENOTTY; return ENOTTY;
auto pts_name = master_pty->pts_name(); auto pts_name = master_pty->pts_name();
if (size < pts_name.length() + 1) if (size < pts_name.length() + 1)
return -ERANGE; return ERANGE;
if (!copy_to_user(buffer, pts_name.characters(), pts_name.length() + 1)) if (!copy_to_user(buffer, pts_name.characters(), pts_name.length() + 1))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -28,7 +28,7 @@
namespace Kernel { namespace Kernel {
mode_t Process::sys$umask(mode_t mask) KResultOr<mode_t> Process::sys$umask(mode_t mask)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
auto old_mask = m_umask; auto old_mask = m_umask;

View file

@ -28,7 +28,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$uname(Userspace<utsname*> user_buf) KResultOr<int> Process::sys$uname(Userspace<utsname*> user_buf)
{ {
extern String* g_hostname; extern String* g_hostname;
extern Lock* g_hostname_lock; extern Lock* g_hostname_lock;
@ -37,7 +37,7 @@ int Process::sys$uname(Userspace<utsname*> user_buf)
LOCKER(*g_hostname_lock, Lock::Mode::Shared); LOCKER(*g_hostname_lock, Lock::Mode::Shared);
if (g_hostname->length() + 1 > sizeof(utsname::nodename)) if (g_hostname->length() + 1 > sizeof(utsname::nodename))
return -ENAMETOOLONG; return ENAMETOOLONG;
utsname buf {}; utsname buf {};
memcpy(buf.sysname, "SerenityOS", 11); memcpy(buf.sysname, "SerenityOS", 11);
@ -47,7 +47,7 @@ int Process::sys$uname(Userspace<utsname*> user_buf)
memcpy(buf.nodename, g_hostname->characters(), g_hostname->length() + 1); memcpy(buf.nodename, g_hostname->characters(), g_hostname->length() + 1);
if (!copy_to_user(user_buf, &buf)) if (!copy_to_user(user_buf, &buf))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$unlink(Userspace<const char*> user_path, size_t path_length) KResultOr<int> Process::sys$unlink(Userspace<const char*> user_path, size_t path_length)
{ {
REQUIRE_PROMISE(cpath); REQUIRE_PROMISE(cpath);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);

View file

@ -32,11 +32,11 @@
namespace Kernel { namespace Kernel {
int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params) KResultOr<int> Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
{ {
Syscall::SC_unveil_params params; Syscall::SC_unveil_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
if (!params.path.characters && !params.permissions.characters) { if (!params.path.characters && !params.permissions.characters) {
m_veil_state = VeilState::Locked; m_veil_state = VeilState::Locked;
@ -44,24 +44,24 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
} }
if (m_veil_state == VeilState::Locked) if (m_veil_state == VeilState::Locked)
return -EPERM; return EPERM;
if (!params.path.characters || !params.permissions.characters) if (!params.path.characters || !params.permissions.characters)
return -EINVAL; return EINVAL;
if (params.permissions.length > 5) if (params.permissions.length > 5)
return -EINVAL; return EINVAL;
auto path = get_syscall_path_argument(params.path); auto path = get_syscall_path_argument(params.path);
if (path.is_error()) if (path.is_error())
return path.error(); return path.error();
if (path.value().is_empty() || path.value().characters()[0] != '/') if (path.value().is_empty() || path.value().characters()[0] != '/')
return -EINVAL; return EINVAL;
auto permissions = copy_string_from_user(params.permissions); auto permissions = copy_string_from_user(params.permissions);
if (permissions.is_null()) if (permissions.is_null())
return -EFAULT; return EFAULT;
// Let's work out permissions first... // Let's work out permissions first...
unsigned new_permissions = 0; unsigned new_permissions = 0;
@ -83,7 +83,7 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
new_permissions |= UnveilAccess::Browse; new_permissions |= UnveilAccess::Browse;
break; break;
default: default:
return -EINVAL; return EINVAL;
} }
} }
@ -114,7 +114,7 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
// as that would be the first time this path is unveiled. // as that would be the first time this path is unveiled.
if (old_permissions != UnveilAccess::None || !matching_node.permissions_inherited_from_root()) { if (old_permissions != UnveilAccess::None || !matching_node.permissions_inherited_from_root()) {
if (new_permissions & ~old_permissions) if (new_permissions & ~old_permissions)
return -EPERM; return EPERM;
} }
matching_node.set_metadata({ matching_node.path(), (UnveilAccess)new_permissions, true, false }); matching_node.set_metadata({ matching_node.path(), (UnveilAccess)new_permissions, true, false });
return 0; return 0;

View file

@ -30,7 +30,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$utime(Userspace<const char*> user_path, size_t path_length, Userspace<const struct utimbuf*> user_buf) KResultOr<int> Process::sys$utime(Userspace<const char*> user_path, size_t path_length, Userspace<const struct utimbuf*> user_buf)
{ {
REQUIRE_PROMISE(fattr); REQUIRE_PROMISE(fattr);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);
@ -39,7 +39,7 @@ int Process::sys$utime(Userspace<const char*> user_path, size_t path_length, Use
utimbuf buf; utimbuf buf;
if (user_buf) { if (user_buf) {
if (!copy_from_user(&buf, user_buf)) if (!copy_from_user(&buf, user_buf))
return -EFAULT; return EFAULT;
} else { } else {
auto now = kgettimeofday(); auto now = kgettimeofday();
buf = { now.tv_sec, now.tv_sec }; buf = { now.tv_sec, now.tv_sec };

View file

@ -38,13 +38,13 @@ KResultOr<siginfo_t> Process::do_waitid(idtype_t idtype, int id, int options)
return result; return result;
} }
pid_t Process::sys$waitid(Userspace<const Syscall::SC_waitid_params*> user_params) KResultOr<pid_t> Process::sys$waitid(Userspace<const Syscall::SC_waitid_params*> user_params)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
Syscall::SC_waitid_params params; Syscall::SC_waitid_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return -EFAULT; return EFAULT;
switch (params.idtype) { switch (params.idtype) {
case P_ALL: case P_ALL:
@ -62,7 +62,7 @@ pid_t Process::sys$waitid(Userspace<const Syscall::SC_waitid_params*> user_param
return siginfo_or_error.error(); return siginfo_or_error.error();
if (!copy_to_user(params.infop, &siginfo_or_error.value())) if (!copy_to_user(params.infop, &siginfo_or_error.value()))
return -EFAULT; return EFAULT;
return 0; return 0;
} }

View file

@ -31,7 +31,7 @@
namespace Kernel { namespace Kernel {
int Process::sys$watch_file(Userspace<const char*> user_path, size_t path_length) KResultOr<int> Process::sys$watch_file(Userspace<const char*> user_path, size_t path_length)
{ {
REQUIRE_PROMISE(rpath); REQUIRE_PROMISE(rpath);
auto path = get_syscall_path_argument(user_path, path_length); auto path = get_syscall_path_argument(user_path, path_length);
@ -46,7 +46,7 @@ int Process::sys$watch_file(Userspace<const char*> user_path, size_t path_length
auto& inode = custody->inode(); auto& inode = custody->inode();
if (!inode.fs().supports_watchers()) if (!inode.fs().supports_watchers())
return -ENOTSUP; return ENOTSUP;
int fd = alloc_fd(); int fd = alloc_fd();
if (fd < 0) if (fd < 0)

View file

@ -31,57 +31,57 @@
namespace Kernel { namespace Kernel {
ssize_t Process::sys$writev(int fd, Userspace<const struct iovec*> iov, int iov_count) KResultOr<ssize_t> Process::sys$writev(int fd, Userspace<const struct iovec*> iov, int iov_count)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (iov_count < 0) if (iov_count < 0)
return -EINVAL; return EINVAL;
// Arbitrary pain threshold. // Arbitrary pain threshold.
if (iov_count > (int)MiB) if (iov_count > (int)MiB)
return -EFAULT; return EFAULT;
u64 total_length = 0; u64 total_length = 0;
Vector<iovec, 32> vecs; Vector<iovec, 32> vecs;
vecs.resize(iov_count); vecs.resize(iov_count);
if (!copy_n_from_user(vecs.data(), iov, iov_count)) if (!copy_n_from_user(vecs.data(), iov, iov_count))
return -EFAULT; return EFAULT;
for (auto& vec : vecs) { for (auto& vec : vecs) {
total_length += vec.iov_len; total_length += vec.iov_len;
if (total_length > NumericLimits<i32>::max()) if (total_length > NumericLimits<i32>::max())
return -EINVAL; return EINVAL;
} }
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_writable()) if (!description->is_writable())
return -EBADF; return EBADF;
int nwritten = 0; int nwritten = 0;
for (auto& vec : vecs) { for (auto& vec : vecs) {
auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len); auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len);
if (!buffer.has_value()) if (!buffer.has_value())
return -EFAULT; return EFAULT;
int rc = do_write(*description, buffer.value(), vec.iov_len); auto result = do_write(*description, buffer.value(), vec.iov_len);
if (rc < 0) { if (result.is_error()) {
if (nwritten == 0) if (nwritten == 0)
return rc; return result.error();
return nwritten; return nwritten;
} }
nwritten += rc; nwritten += result.value();
} }
return nwritten; return nwritten;
} }
ssize_t Process::do_write(FileDescription& description, const UserOrKernelBuffer& data, size_t data_size) KResultOr<ssize_t> Process::do_write(FileDescription& description, const UserOrKernelBuffer& data, size_t data_size)
{ {
ssize_t total_nwritten = 0; ssize_t total_nwritten = 0;
if (!description.is_blocking()) { if (!description.is_blocking()) {
if (!description.can_write()) if (!description.can_write())
return -EAGAIN; return EAGAIN;
} }
if (description.should_append()) if (description.should_append())
@ -97,7 +97,7 @@ ssize_t Process::do_write(FileDescription& description, const UserOrKernelBuffer
auto unblock_flags = Thread::FileBlocker::BlockFlags::None; auto unblock_flags = Thread::FileBlocker::BlockFlags::None;
if (Thread::current()->block<Thread::WriteBlocker>({}, description, unblock_flags).was_interrupted()) { if (Thread::current()->block<Thread::WriteBlocker>({}, description, unblock_flags).was_interrupted()) {
if (total_nwritten == 0) if (total_nwritten == 0)
return -EINTR; return EINTR;
} }
// TODO: handle exceptions in unblock_flags // TODO: handle exceptions in unblock_flags
} }
@ -114,24 +114,24 @@ ssize_t Process::do_write(FileDescription& description, const UserOrKernelBuffer
return total_nwritten; return total_nwritten;
} }
ssize_t Process::sys$write(int fd, const u8* data, ssize_t size) KResultOr<ssize_t> Process::sys$write(int fd, const u8* data, ssize_t size)
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
if (size < 0) if (size < 0)
return -EINVAL; return EINVAL;
if (size == 0) if (size == 0)
return 0; return 0;
dbgln_if(IO_DEBUG, "sys$write({}, {}, {})", fd, data, size); dbgln_if(IO_DEBUG, "sys$write({}, {}, {})", fd, data, size);
auto description = file_description(fd); auto description = file_description(fd);
if (!description) if (!description)
return -EBADF; return EBADF;
if (!description->is_writable()) if (!description->is_writable())
return -EBADF; return EBADF;
auto buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>(data), (size_t)size); auto buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>(data), (size_t)size);
if (!buffer.has_value()) if (!buffer.has_value())
return -EFAULT; return EFAULT;
return do_write(*description, buffer.value(), size); return do_write(*description, buffer.value(), size);
} }