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
Notes: sideshowbarker 2024-07-18 21:49:02 +09:00
70 changed files with 747 additions and 742 deletions

View file

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

View file

@ -69,7 +69,7 @@ asm(
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()
{
@ -78,14 +78,15 @@ UNMAP_AFTER_INIT void initialize()
}
#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),
static Handler s_syscall_table[] = {
ENUMERATE_SYSCALLS(__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();
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)
process.sys$exit((int)arg1);
process.sys$exit(arg1);
else
process.sys$exit_thread(arg1);
VERIFY_NOT_REACHED();
return 0;
}
if (function == SC_fork)
return process.sys$fork(regs);
if (function == SC_sigreturn)
return process.sys$sigreturn(regs);
if (function == SC_fork || function == SC_sigreturn) {
// These syscalls want the RegisterState& rather than individual parameters.
auto handler = (HandlerWithRegisterState)s_syscall_table[function];
return (process.*(handler))(regs);
}
if (function >= Function::__Count) {
dbgln("Unknown syscall {} requested ({:08x}, {:08x}, {:08x})", function, arg1, arg2, arg3);
@ -162,7 +162,7 @@ void syscall_handler(TrapFrame* trap)
asm volatile(""
: "=m"(*ptr));
static constexpr u32 iopl_mask = 3u << 12;
static constexpr FlatPtr iopl_mask = 3u << 12;
if ((regs.eflags & (iopl_mask)) != 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);
}
u32 function = regs.eax;
u32 arg1 = regs.edx;
u32 arg2 = regs.ecx;
u32 arg3 = regs.ebx;
regs.eax = Syscall::handle(regs, function, arg1, arg2, arg3);
auto function = regs.eax;
auto arg1 = regs.edx;
auto arg2 = regs.ecx;
auto arg3 = regs.ebx;
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();

View file

@ -30,7 +30,7 @@
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);
auto path = get_syscall_path_argument(user_path, path_length);

View file

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

View file

@ -31,15 +31,15 @@
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);
if (!size)
return -EINVAL;
return EINVAL;
if (size % PAGE_SIZE)
return -EINVAL;
return EINVAL;
int new_fd = alloc_fd();
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);
if (!vmobject)
return -ENOMEM;
return ENOMEM;
auto anon_file = AnonymousFile::create(vmobject.release_nonnull());
auto description_or_error = FileDescription::create(*anon_file);

View file

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

View file

@ -31,7 +31,7 @@
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);
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;
}
int Process::sys$fchdir(int fd)
KResultOr<int> Process::sys$fchdir(int fd)
{
REQUIRE_PROMISE(stdio);
auto description = file_description(fd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_directory())
return -ENOTDIR;
return ENOTDIR;
if (!description->metadata().may_execute(*this))
return -EACCES;
return EACCES;
m_cwd = description->custody();
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);
@ -70,7 +70,7 @@ int Process::sys$getcwd(Userspace<char*> buffer, size_t size)
size_t ideal_size = path.length() + 1;
auto size_to_copy = min(ideal_size, size);
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.
return ideal_size;
}

View file

@ -31,7 +31,7 @@
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);
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());
}
int Process::sys$fchmod(int fd, mode_t mode)
KResultOr<int> Process::sys$fchmod(int fd, mode_t mode)
{
REQUIRE_PROMISE(fattr);
auto description = file_description(fd);
if (!description)
return -EBADF;
return EBADF;
return description->chmod(mode);
}

View file

@ -29,21 +29,21 @@
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);
auto description = file_description(fd);
if (!description)
return -EBADF;
return EBADF;
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);
Syscall::SC_chown_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
auto path = get_syscall_path_argument(params.path);
if (path.is_error())
return path.error();

View file

@ -31,10 +31,10 @@
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())
return -EPERM;
return EPERM;
REQUIRE_PROMISE(chroot);
auto path = get_syscall_path_argument(user_path, path_length);
if (path.is_error())

View file

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

View file

@ -31,26 +31,26 @@
namespace Kernel {
int Process::sys$dump_backtrace()
KResultOr<int> Process::sys$dump_backtrace()
{
dump_backtrace();
return 0;
}
int Process::sys$dbgputch(u8 ch)
KResultOr<int> Process::sys$dbgputch(u8 ch)
{
IO::out8(0xe9, ch);
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)
return 0;
auto buffer = UserOrKernelBuffer::for_user_buffer(characters, length);
if (!buffer.has_value())
return -EFAULT;
return EFAULT;
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)
IO::out8(0xe9, buffer[i]);

View file

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

View file

@ -29,16 +29,16 @@
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);
auto description = file_description(old_fd);
if (!description)
return -EBADF;
return EBADF;
if (old_fd == new_fd)
return 0;
if (new_fd < 0 || new_fd >= m_max_open_file_descriptors)
return -EINVAL;
return EINVAL;
m_fds[new_fd].set(*description);
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)
return -EINVAL;
return EINVAL;
auto main_program_load_range_result = get_required_load_range(main_program_description);
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 (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);
}
@ -876,7 +876,7 @@ KResult Process::exec(String path, Vector<String> arguments, Vector<String> envi
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);
@ -884,10 +884,10 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
// On success, the kernel stack will be lost.
Syscall::SC_execve_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
return -E2BIG;
return E2BIG;
String path;
{
@ -919,11 +919,11 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
Vector<String> arguments;
if (!copy_user_strings(params.arguments, arguments))
return -EFAULT;
return EFAULT;
Vector<String> environment;
if (!copy_user_strings(params.environment, environment))
return -EFAULT;
return EFAULT;
auto result = exec(move(path), move(arguments), move(environment));
VERIFY(result.is_error()); // We should never continue after a successful exec!

View file

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

View file

@ -32,13 +32,13 @@
namespace Kernel {
pid_t Process::sys$fork(RegisterState& regs)
KResultOr<pid_t> Process::sys$fork(RegisterState& regs)
{
REQUIRE_PROMISE(proc);
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));
if (!child_first_thread)
return -ENOMEM;
return ENOMEM;
child->m_root_directory = m_root_directory;
child->m_root_directory_relative_to_global_root = m_root_directory_relative_to_global_root;
child->m_promises = m_promises;
@ -85,7 +85,7 @@ pid_t Process::sys$fork(RegisterState& regs)
if (!region_clone) {
dbgln("fork: Cannot clone region, insufficient memory");
// TODO: tear down new process?
return -ENOMEM;
return ENOMEM;
}
auto& child_region = child->space().add_region(region_clone.release_nonnull());

View file

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

View file

@ -102,13 +102,13 @@ void Process::clear_futex_queues_on_exec()
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);
Syscall::SC_futex_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
Thread::BlockTimeout timeout;
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) {
timespec ts_stimeout { 0, 0 };
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;
bool is_absolute = cmd != FUTEX_WAIT;
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) {
auto region = space().find_region_containing(Range { VirtualAddress { user_address_or_offset }, sizeof(u32) });
if (!region)
return -EFAULT;
return EFAULT;
vmobject = region->vmobject();
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: {
auto region2 = space().find_region_containing(Range { VirtualAddress { user_address_or_offset2 }, sizeof(u32) });
if (!region2)
return -EFAULT;
return EFAULT;
vmobject2 = region2->vmobject();
user_address_or_offset2 = region->offset_in_vmobject_from_vaddr(VirtualAddress(user_address_or_offset2));
break;
@ -226,10 +226,10 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
auto do_wait = [&](u32 bitset) -> int {
auto user_value = user_atomic_load_relaxed(params.userspace_address);
if (!user_value.has_value())
return -EFAULT;
return EFAULT;
if (user_value.value() != 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);
@ -248,7 +248,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
remove_futex_queue(vmobject, user_address_or_offset);
}
if (block_result == Thread::BlockResult::InterruptedByTimeout) {
return -ETIMEDOUT;
return ETIMEDOUT;
}
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 user_value = user_atomic_load_relaxed(params.userspace_address);
if (!user_value.has_value())
return -EFAULT;
return EFAULT;
if (val3.has_value() && val3.value() != user_value.value())
return -EAGAIN;
return EAGAIN;
atomic_thread_fence(AK::MemoryOrder::memory_order_acquire);
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);
break;
default:
return -EINVAL;
return EINVAL;
}
if (!oldval.has_value())
return -EFAULT;
return EFAULT;
atomic_thread_fence(AK::MemoryOrder::memory_order_acquire);
int result = do_wake(vmobject.ptr(), user_address_or_offset, params.val, {});
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));
break;
default:
return -EINVAL;
return EINVAL;
}
if (compare_result)
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:
VERIFY(params.val3 != FUTEX_BITSET_MATCH_ANY); // we should have turned it into FUTEX_WAIT
if (params.val3 == 0)
return -EINVAL;
return EINVAL;
return do_wait(params.val3);
case FUTEX_WAKE_BITSET:
VERIFY(params.val3 != FUTEX_BITSET_MATCH_ANY); // we should have turned it into FUTEX_WAKE
if (params.val3 == 0)
return -EINVAL;
return EINVAL;
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 {
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);
if (size < 0)
return -EINVAL;
return EINVAL;
auto description = file_description(fd);
if (!description)
return -EBADF;
return EBADF;
auto user_buffer = UserOrKernelBuffer::for_user_buffer((u8*)buffer, size);
if (!user_buffer.has_value())
return -EFAULT;
return EFAULT;
return description->get_dir_entries(user_buffer.value(), size);
}

View file

@ -30,7 +30,7 @@
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;
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();
size_t stack_size = stack_region->size();
if (!copy_to_user(user_stack_base, &stack_base))
return -EFAULT;
return EFAULT;
if (!copy_to_user(user_stack_size, &stack_size))
return -EFAULT;
return EFAULT;
return 0;
}

View file

@ -33,15 +33,15 @@ namespace Kernel {
// 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
// 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);
if (buffer_size <= 0)
return -EINVAL;
return EINVAL;
auto data_buffer = UserOrKernelBuffer::for_user_buffer(buffer, buffer_size);
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) {
get_good_random_bytes(buffer, buffer_bytes);
return (ssize_t)buffer_bytes;

View file

@ -28,58 +28,58 @@
namespace Kernel {
uid_t Process::sys$getuid()
KResultOr<uid_t> Process::sys$getuid()
{
REQUIRE_PROMISE(stdio);
return m_uid;
}
gid_t Process::sys$getgid()
KResultOr<gid_t> Process::sys$getgid()
{
REQUIRE_PROMISE(stdio);
return m_gid;
}
uid_t Process::sys$geteuid()
KResultOr<uid_t> Process::sys$geteuid()
{
REQUIRE_PROMISE(stdio);
return m_euid;
}
gid_t Process::sys$getegid()
KResultOr<gid_t> Process::sys$getegid()
{
REQUIRE_PROMISE(stdio);
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);
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;
}
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);
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;
}
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);
if (count < 0)
return -EINVAL;
return EINVAL;
if (!count)
return 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))
return -EFAULT;
return EFAULT;
return 0;
}

View file

@ -31,32 +31,32 @@ namespace Kernel {
extern String* g_hostname;
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);
if (size < 0)
return -EINVAL;
return EINVAL;
LOCKER(*g_hostname_lock, Lock::Mode::Shared);
if ((size_t)size < (g_hostname->length() + 1))
return -ENAMETOOLONG;
return ENAMETOOLONG;
if (!copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1))
return -EFAULT;
return EFAULT;
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;
if (!is_superuser())
return -EPERM;
return EPERM;
if (length < 0)
return -EINVAL;
return EINVAL;
LOCKER(*g_hostname_lock, Lock::Mode::Exclusive);
if (length > 64)
return -ENAMETOOLONG;
return ENAMETOOLONG;
auto copied_hostname = copy_string_from_user(hostname, length);
if (copied_hostname.is_null())
return -EFAULT;
return EFAULT;
*g_hostname = move(copied_hostname);
return 0;
}

View file

@ -29,11 +29,11 @@
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);
if (!description)
return -EBADF;
return EBADF;
return description->file().ioctl(*description, request, arg);
}

View file

@ -31,68 +31,68 @@ namespace Kernel {
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);
if (!is_superuser())
return -EPERM;
return EPERM;
Syscall::SC_setkeymap_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
Keyboard::CharacterMapData character_map_data;
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))
return -EFAULT;
return EFAULT;
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))
return -EFAULT;
return EFAULT;
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);
if (map_name.is_error()) {
return map_name.error();
}
if (map_name.value().length() > map_name_max_size) {
return -ENAMETOOLONG;
return ENAMETOOLONG;
}
KeyboardDevice::the().set_maps(character_map_data, map_name.value());
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);
Syscall::SC_getkeymap_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
String keymap_name = KeyboardDevice::the().keymap_name();
const Keyboard::CharacterMapData& character_maps = KeyboardDevice::the().character_maps();
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)))
return -EFAULT;
return EFAULT;
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)))
return -EFAULT;
return EFAULT;
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())
return -ENAMETOOLONG;
return ENAMETOOLONG;
if (!copy_to_user(params.map_name.data, keymap_name.characters(), keymap_name.length()))
return -EFAULT;
return EFAULT;
return 0;
}

View file

@ -117,7 +117,7 @@ KResult Process::do_killself(int signal)
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())
REQUIRE_PROMISE(stdio);
@ -125,10 +125,10 @@ int Process::sys$kill(pid_t pid_or_pgid, int signal)
REQUIRE_PROMISE(proc);
if (signal < 0 || signal >= 32)
return -EINVAL;
return EINVAL;
if (pid_or_pgid < -1) {
if (pid_or_pgid == NumericLimits<i32>::min())
return -EINVAL;
return EINVAL;
return do_killpg(-pid_or_pgid, signal);
}
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);
auto peer = Process::from_pid(pid_or_pgid);
if (!peer)
return -ESRCH;
return ESRCH;
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);
if (signum < 1 || signum >= 32)
return -EINVAL;
return EINVAL;
if (pgrp < 0)
return -EINVAL;
return EINVAL;
return do_killpg(pgrp, signum);
}

View file

@ -30,27 +30,27 @@
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);
Syscall::SC_link_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
auto old_path = copy_string_from_user(params.old_path);
if (old_path.is_null())
return -EFAULT;
return EFAULT;
auto new_path = copy_string_from_user(params.new_path);
if (new_path.is_null())
return -EFAULT;
return EFAULT;
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);
Syscall::SC_symlink_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
auto target = get_syscall_path_argument(params.target);
if (target.is_error())
return target.error();

View file

@ -29,12 +29,12 @@
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);
auto description = file_description(fd);
if (!description)
return -EBADF;
return EBADF;
return description->seek(offset, whence);
}

View file

@ -30,7 +30,7 @@
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);
auto path = get_syscall_path_argument(user_path, path_length);

View file

@ -30,14 +30,14 @@
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);
Syscall::SC_mknod_params 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))
return -EPERM;
return EPERM;
auto path = get_syscall_path_argument(params.path);
if (path.is_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;
}
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);
Syscall::SC_mmap_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
void* addr = (void*)params.addr;
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)
return -EINVAL;
return EINVAL;
if (page_round_up_would_wrap(size))
return -EINVAL;
return EINVAL;
if (!is_user_range(VirtualAddress(addr), page_round_up(size)))
return -EFAULT;
return EFAULT;
String name;
if (params.name.characters) {
if (params.name.length > PATH_MAX)
return -ENAMETOOLONG;
return ENAMETOOLONG;
name = copy_string_from_user(params.name);
if (name.is_null())
return -EFAULT;
return EFAULT;
}
if (size == 0)
return -EINVAL;
return EINVAL;
if ((FlatPtr)addr & ~PAGE_MASK)
return -EINVAL;
return EINVAL;
bool map_shared = flags & MAP_SHARED;
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;
if (map_shared && map_private)
return -EINVAL;
return EINVAL;
if (!map_shared && !map_private)
return -EINVAL;
return EINVAL;
if (map_fixed && map_randomized)
return -EINVAL;
return EINVAL;
if (!validate_mmap_prot(prot, map_stack, map_anonymous))
return -EINVAL;
return EINVAL;
if (map_stack && (!map_private || !map_anonymous))
return -EINVAL;
return EINVAL;
Region* region = nullptr;
Optional<Range> range;
@ -223,7 +223,7 @@ FlatPtr Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
}
if (!range.has_value())
return -ENOMEM;
return ENOMEM;
if (map_anonymous) {
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();
} else {
if (offset < 0)
return -EINVAL;
return EINVAL;
if (static_cast<size_t>(offset) & ~PAGE_MASK)
return -EINVAL;
return EINVAL;
auto description = file_description(fd);
if (!description)
return -EBADF;
return EBADF;
if (description->is_directory())
return -ENODEV;
return ENODEV;
// Require read access even when read protection is not requested.
if (!description->is_readable())
return -EACCES;
return EACCES;
if (map_shared) {
if ((prot & PROT_WRITE) && !description->is_writable())
return -EACCES;
return EACCES;
}
if (description->inode()) {
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);
@ -260,7 +260,7 @@ FlatPtr Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
}
if (!region)
return -ENOMEM;
return ENOMEM;
region->set_mmap(true);
if (map_shared)
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() };
}
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);
@ -302,21 +302,21 @@ int Process::sys$mprotect(void* addr, size_t size, int prot)
auto range_to_mprotect = range_or_error.value();
if (!range_to_mprotect.size())
return -EINVAL;
return EINVAL;
if (!is_user_range(range_to_mprotect))
return -EFAULT;
return EFAULT;
if (auto* whole_region = space().find_region_from_range(range_to_mprotect)) {
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))
return -EINVAL;
return EINVAL;
if (whole_region->access() == prot_to_region_access_flags(prot))
return 0;
if (whole_region->vmobject().is_inode()
&& !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_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
if (auto* old_region = space().find_region_containing(range_to_mprotect)) {
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))
return -EINVAL;
return EINVAL;
if (old_region->access() == prot_to_region_access_flags(prot))
return 0;
if (old_region->vmobject().is_inode()
&& !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.
@ -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)
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);
@ -377,31 +377,31 @@ int Process::sys$madvise(void* address, size_t size, int advice)
auto range_to_madvise = range_or_error.value();
if (!range_to_madvise.size())
return -EINVAL;
return EINVAL;
if (!is_user_range(range_to_madvise))
return -EFAULT;
return EFAULT;
auto* region = space().find_region_from_range(range_to_madvise);
if (!region)
return -EINVAL;
return EINVAL;
if (!region->is_mmap())
return -EPERM;
return EPERM;
bool set_volatile = advice & MADV_SET_VOLATILE;
bool set_nonvolatile = advice & MADV_SET_NONVOLATILE;
if (set_volatile && set_nonvolatile)
return -EINVAL;
return EINVAL;
if (set_volatile || set_nonvolatile) {
if (!region->vmobject().is_anonymous())
return -EPERM;
return EPERM;
bool was_purged = false;
switch (region->set_volatile(VirtualAddress(address), size, set_volatile, was_purged)) {
case Region::SetVolatileError::Success:
break;
case Region::SetVolatileError::NotPurgeable:
return -EPERM;
return EPERM;
case Region::SetVolatileError::OutOfMemory:
return -ENOMEM;
return ENOMEM;
}
if (set_nonvolatile)
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 (!region->vmobject().is_anonymous())
return -EPERM;
return EPERM;
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);
Syscall::SC_set_mmap_name_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
if (params.name.length > PATH_MAX)
return -ENAMETOOLONG;
return ENAMETOOLONG;
auto name = copy_string_from_user(params.name);
if (name.is_null())
return -EFAULT;
return EFAULT;
auto range_or_error = expand_range_to_page_boundaries((FlatPtr)params.addr, params.size);
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);
if (!region)
return -EINVAL;
return EINVAL;
if (!region->is_mmap())
return -EPERM;
return EPERM;
region->set_name(move(name));
return 0;
}
int Process::sys$munmap(void* addr, size_t size)
KResultOr<int> Process::sys$munmap(void* addr, size_t size)
{
REQUIRE_PROMISE(stdio);
if (!size)
return -EINVAL;
return EINVAL;
auto range_or_error = expand_range_to_page_boundaries((FlatPtr)addr, size);
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();
if (!is_user_range(range_to_unmap))
return -EFAULT;
return EFAULT;
if (auto* whole_region = space().find_region_from_range(range_to_unmap)) {
if (!whole_region->is_mmap())
return -EPERM;
return EPERM;
bool success = space().deallocate_region(*whole_region);
VERIFY(success);
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 (!old_region->is_mmap())
return -EPERM;
return EPERM;
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)
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);
Syscall::SC_mremap_params 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);
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);
if (!old_region)
return -EINVAL;
return EINVAL;
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))) {
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);
return -ENOTIMPL;
return ENOTIMPL;
}
FlatPtr Process::sys$allocate_tls(size_t size)
KResultOr<FlatPtr> Process::sys$allocate_tls(size_t size)
{
REQUIRE_PROMISE(stdio);
if (!size)
return -EINVAL;
return EINVAL;
if (!m_master_tls_region.is_null())
return -EEXIST;
return EEXIST;
if (thread_count() != 1)
return -EFAULT;
return EFAULT;
Thread* main_thread = nullptr;
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);
if (!range.has_value())
return -ENOMEM;
return ENOMEM;
auto region_or_error = space().allocate_region(range.value(), String(), PROT_READ | PROT_WRITE);
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({});
if (tsr_result.is_error())
return -EFAULT;
return EFAULT;
auto& tls_descriptor = Processor::current().get_gdt_entry(GDT_SELECTOR_TLS);
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();
}
int Process::sys$msyscall(void* address)
KResultOr<int> Process::sys$msyscall(void* address)
{
if (space().enforces_syscall_regions())
return -EPERM;
return EPERM;
if (!address) {
space().set_enforces_syscall_regions(true);
@ -593,14 +593,14 @@ int Process::sys$msyscall(void* address)
}
if (!is_user_address(VirtualAddress { address }))
return -EFAULT;
return EFAULT;
auto* region = space().find_region_containing(Range { VirtualAddress { address }, 1 });
if (!region)
return -EINVAL;
return EINVAL;
if (!region->is_mmap())
return -EINVAL;
return EINVAL;
region->set_syscall_region(true);
return 0;

View file

@ -35,10 +35,10 @@ namespace Kernel {
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())
return -EPERM;
return EPERM;
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());
if (!elf_image->parse())
return -ENOEXEC;
return ENOEXEC;
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)
return -EINVAL;
return EINVAL;
auto* text_base = section_storage_by_name.get(".text").value_or(nullptr);
if (!text_base) {
dbgln("No .text section found in module!");
return -EINVAL;
return EINVAL;
}
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)
return -EINVAL;
return EINVAL;
if (g_modules->contains(module->name)) {
dbgln("a module with the name {} is already loaded; please unload it first", module->name);
return -EEXIST;
return EEXIST;
}
module->module_init();
@ -162,20 +162,20 @@ int Process::sys$module_load(Userspace<const char*> user_path, size_t path_lengt
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())
return -EPERM;
return EPERM;
REQUIRE_NO_PROMISES;
auto module_name = copy_string_from_user(user_name, name_length);
if (module_name.is_null())
return -EFAULT;
return EFAULT;
auto it = g_modules->find(module_name);
if (it == g_modules->end())
return -ENOENT;
return ENOENT;
if (it->value->module_fini)
it->value->module_fini();

View file

@ -36,24 +36,24 @@
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())
return -EPERM;
return EPERM;
REQUIRE_NO_PROMISES;
Syscall::SC_mount_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
auto source_fd = params.source_fd;
auto target = copy_string_from_user(params.target);
if (target.is_null())
return -EFAULT;
return EFAULT;
auto fs_type = copy_string_from_user(params.fs_type);
if (fs_type.is_null())
return -EFAULT;
return EFAULT;
auto description = file_description(source_fd);
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) {
// We're doing a bind mount.
if (description.is_null())
return -EBADF;
return EBADF;
if (!description->custody()) {
// We only support bind-mounting inodes, not arbitrary files.
return -ENODEV;
return ENODEV;
}
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 (description.is_null())
return -EBADF;
return EBADF;
if (!description->file().is_block_device())
return -ENOTBLK;
return ENOTBLK;
if (!description->file().is_seekable()) {
dbgln("mount: this is not a seekable file");
return -ENODEV;
return ENODEV;
}
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);
} else if (fs_type == "9p" || fs_type == "Plan9FS") {
if (description.is_null())
return -EBADF;
return EBADF;
fs = Plan9FS::create(*description);
} 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") {
fs = TmpFS::create();
} else {
return -ENODEV;
return ENODEV;
}
if (!fs->initialize()) {
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);
@ -128,10 +128,10 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
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())
return -EPERM;
return EPERM;
REQUIRE_NO_PROMISES;

View file

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

View file

@ -29,7 +29,7 @@
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);
}

View file

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

View file

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

View file

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

View file

@ -29,61 +29,61 @@
namespace Kernel {
pid_t Process::sys$getpid()
KResultOr<pid_t> Process::sys$getpid()
{
REQUIRE_PROMISE(stdio);
return m_pid.value();
}
pid_t Process::sys$getppid()
KResultOr<pid_t> Process::sys$getppid()
{
REQUIRE_PROMISE(stdio);
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);
if (m_name.length() + 1 > buffer_size)
return -ENAMETOOLONG;
return ENAMETOOLONG;
if (!copy_to_user(buffer, m_name.characters(), m_name.length() + 1))
return -EFAULT;
return EFAULT;
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);
if (user_name_length > 256)
return -ENAMETOOLONG;
return ENAMETOOLONG;
auto name = copy_string_from_user(user_name, user_name_length);
if (name.is_null())
return -EFAULT;
return EFAULT;
// Empty and whitespace-only names only exist to confuse users.
if (name.is_whitespace())
return -EINVAL;
return EINVAL;
m_name = move(name);
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;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
if (params.key.length == 0 || params.key.length > 16 * KiB)
return -EINVAL;
return EINVAL;
if (params.value.length > 16 * KiB)
return -EINVAL;
return EINVAL;
auto copied_key = copy_string_from_user(params.key.characters, params.key.length);
if (copied_key.is_null())
return -EFAULT;
return EFAULT;
auto copied_value = copy_string_from_user(params.value.characters, params.value.length);
if (copied_value.is_null())
return -EFAULT;
return EFAULT;
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));
return 0;
}

View file

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

View file

@ -160,12 +160,12 @@ static KResultOr<u32> handle_ptrace(const Kernel::Syscall::SC_ptrace_params& par
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);
Syscall::SC_ptrace_params params {};
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
auto result = handle_ptrace(params, *this);
return result.is_error() ? result.error().error() : result.value();
}

View file

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

View file

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

View file

@ -31,13 +31,13 @@
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);
Syscall::SC_readlink_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
auto path = get_syscall_path_argument(params.path);
if (path.is_error())
@ -49,7 +49,7 @@ int Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_par
auto description = result.value();
if (!description->metadata().is_symlink())
return -EINVAL;
return EINVAL;
auto contents = description->read_entire_file();
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 size_to_copy = min(link_target.size(), params.buffer.size);
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.
return link_target.size();
}

View file

@ -31,13 +31,13 @@
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);
Syscall::SC_realpath_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
auto path = get_syscall_path_argument(params.path);
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;
auto size_to_copy = min(ideal_size, params.buffer.size);
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.
return ideal_size;
};

View file

@ -30,12 +30,12 @@
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);
Syscall::SC_rename_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
auto old_path = get_syscall_path_argument(params.old_path);
if (old_path.is_error())
return old_path.error();

View file

@ -30,7 +30,7 @@
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);
auto path = get_syscall_path_argument(user_path, path_length);

View file

@ -28,36 +28,36 @@
namespace Kernel {
int Process::sys$yield()
KResultOr<int> Process::sys$yield()
{
REQUIRE_PROMISE(stdio);
Thread::current()->yield_without_holding_big_lock();
return 0;
}
int Process::sys$donate(pid_t tid)
KResultOr<int> Process::sys$donate(pid_t tid)
{
REQUIRE_PROMISE(stdio);
if (tid < 0)
return -EINVAL;
return EINVAL;
ScopedCritical critical;
auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid())
return -ESRCH;
return ESRCH;
Thread::current()->donate_without_holding_big_lock(thread, "sys$donate");
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);
struct sched_param desired_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)
return -EINVAL;
return EINVAL;
auto* peer = Thread::current();
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);
if (!peer)
return -ESRCH;
return ESRCH;
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);
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);
int priority;
@ -88,10 +88,10 @@ int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_p
}
if (!peer)
return -ESRCH;
return ESRCH;
if (!is_superuser() && m_euid != peer->process().m_uid && m_uid != peer->process().m_uid)
return -EPERM;
return EPERM;
priority = (int)peer->priority();
}
@ -100,7 +100,7 @@ int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_p
priority
};
if (!copy_to_user(user_param, &param))
return -EFAULT;
return EFAULT;
return 0;
}

View file

@ -32,22 +32,22 @@
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);
Syscall::SC_select_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
if (params.nfds < 0)
return -EINVAL;
return EINVAL;
Thread::BlockTimeout timeout;
if (params.timeout) {
timespec timeout_copy;
if (!copy_from_user(&timeout_copy, params.timeout))
return -EFAULT;
return EFAULT;
timeout = Thread::BlockTimeout(false, &timeout_copy);
}
@ -57,7 +57,7 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
if (params.sigmask) {
sigset_t sigmask_copy;
if (!copy_from_user(&sigmask_copy, params.sigmask))
return -EFAULT;
return EFAULT;
previous_signal_mask = current_thread->update_signal_mask(sigmask_copy);
}
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;
if (params.readfds && !copy_from_user(&fds_read, params.readfds))
return -EFAULT;
return EFAULT;
if (params.writefds && !copy_from_user(&fds_write, params.writefds))
return -EFAULT;
return EFAULT;
if (params.exceptfds && !copy_from_user(&fds_except, params.exceptfds))
return -EFAULT;
return EFAULT;
Thread::SelectBlocker::FDVector fds_info;
Vector<int> fds;
@ -89,7 +89,7 @@ int Process::sys$select(const Syscall::SC_select_params* user_params)
auto description = file_description(fd);
if (!description) {
dbgln("sys$select: Bad fd number {}", fd);
return -EBADF;
return EBADF;
}
fds_info.append({ description.release_nonnull(), (Thread::FileBlocker::BlockFlags)block_flags });
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()) {
dbgln_if(POLL_SELECT_DEBUG, "select was interrupted");
return -EINTR;
return EINTR;
}
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))
return -EFAULT;
return EFAULT;
if (params.writefds && !copy_to_user(params.writefds, &fds_write))
return -EFAULT;
return EFAULT;
if (params.exceptfds && !copy_to_user(params.exceptfds, &fds_except))
return -EFAULT;
return EFAULT;
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);
// FIXME: Return -EINVAL if timeout is invalid.
Syscall::SC_poll_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
if (params.nfds >= m_max_open_file_descriptors)
return -ENOBUFS;
return ENOBUFS;
Thread::BlockTimeout timeout;
if (params.timeout) {
timespec timeout_copy;
if (!copy_from_user(&timeout_copy, params.timeout))
return -EFAULT;
return EFAULT;
timeout = Thread::BlockTimeout(false, &timeout_copy);
}
sigset_t sigmask = {};
if (params.sigmask && !copy_from_user(&sigmask, params.sigmask))
return -EFAULT;
return EFAULT;
Vector<pollfd> fds_copy;
if (params.nfds > 0) {
Checked nfds_checked = sizeof(pollfd);
nfds_checked *= params.nfds;
if (nfds_checked.has_overflow())
return -EFAULT;
return EFAULT;
fds_copy.resize(params.nfds);
if (!copy_from_user(fds_copy.data(), &params.fds[0], nfds_checked.value()))
return -EFAULT;
return EFAULT;
}
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);
if (!description) {
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
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);
if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted())
return -EINTR;
return EINTR;
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)))
return -EFAULT;
return EFAULT;
return fds_with_revents;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -30,7 +30,7 @@
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);
auto current_thread = Thread::current();
@ -38,7 +38,7 @@ int Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<
if (set) {
sigset_t set_value;
if (!copy_from_user(&set_value, set))
return -EFAULT;
return EFAULT;
switch (how) {
case SIG_BLOCK:
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);
break;
default:
return -EINVAL;
return EINVAL;
}
} else {
previous_signal_mask = current_thread->signal_mask();
}
if (old_set && !copy_to_user(old_set, &previous_signal_mask))
return -EFAULT;
return EFAULT;
return 0;
}
int Process::sys$sigpending(Userspace<sigset_t*> set)
KResultOr<int> Process::sys$sigpending(Userspace<sigset_t*> set)
{
REQUIRE_PROMISE(stdio);
auto pending_signals = Thread::current()->pending_signals();
if (!copy_to_user(set, &pending_signals))
return -EFAULT;
return EFAULT;
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);
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?
auto& action = Thread::current()->m_signal_action_data[signum];
if (old_act) {
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)))
return -EFAULT;
return EFAULT;
}
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)))
return -EFAULT;
return EFAULT;
return 0;
}
int Process::sys$sigreturn([[maybe_unused]] RegisterState& registers)
KResultOr<int> Process::sys$sigreturn([[maybe_unused]] RegisterState& registers)
{
REQUIRE_PROMISE(stdio);
SmapDisabler disabler;

View file

@ -40,12 +40,12 @@ namespace Kernel {
REQUIRE_PROMISE(unix); \
} 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);
if ((type & SOCK_TYPE_MASK) == SOCK_RAW && !is_superuser())
return -EACCES;
return EACCES;
int fd = alloc_fd();
if (fd < 0)
return fd;
@ -66,59 +66,59 @@ int Process::sys$socket(int domain, int type, int protocol)
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);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
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)
return -EINVAL;
return EINVAL;
auto description = file_description(sockfd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
if (socket.is_connected())
return -EINVAL;
return EINVAL;
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);
socklen_t address_size = 0;
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();
if (accepted_socket_fd < 0)
return accepted_socket_fd;
auto accepting_socket_description = file_description(accepting_socket_fd);
if (!accepting_socket_description)
return -EBADF;
return EBADF;
if (!accepting_socket_description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *accepting_socket_description->socket();
if (!socket.can_accept()) {
if (accepting_socket_description->is_blocking()) {
auto unblock_flags = Thread::FileBlocker::BlockFlags::None;
if (Thread::current()->block<Thread::AcceptBlocker>({}, *accepting_socket_description, unblock_flags).was_interrupted())
return -EINTR;
return EINTR;
} else {
return -EAGAIN;
return EAGAIN;
}
}
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));
accepted_socket->get_peer_address((sockaddr*)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))
return -EFAULT;
return EFAULT;
}
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;
}
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();
if (fd < 0)
return fd;
auto description = file_description(sockfd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
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);
}
int Process::sys$shutdown(int sockfd, int how)
KResultOr<int> Process::sys$shutdown(int sockfd, int how)
{
REQUIRE_PROMISE(stdio);
if (how & ~SHUT_RDWR)
return -EINVAL;
return EINVAL;
auto description = file_description(sockfd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
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);
struct msghdr msg;
if (!copy_from_user(&msg, user_msg))
return -EFAULT;
return EFAULT;
if (msg.msg_iovlen != 1)
return -ENOTSUP; // FIXME: Support this :)
return ENOTSUP; // FIXME: Support this :)
Vector<iovec, 1> iovs;
iovs.resize(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);
socklen_t addr_length = msg.msg_namelen;
auto description = file_description(sockfd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
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);
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);
if (result.is_error())
return result.error();
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);
struct msghdr msg;
if (!copy_from_user(&msg, user_msg))
return -EFAULT;
return EFAULT;
if (msg.msg_iovlen != 1)
return -ENOTSUP; // FIXME: Support this :)
return ENOTSUP; // FIXME: Support this :)
Vector<iovec, 1> iovs;
iovs.resize(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<socklen_t*> user_addr_length(msg.msg_name ? (FlatPtr)&user_msg.unsafe_userspace_ptr()->msg_namelen : 0);
auto description = file_description(sockfd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
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);
if (!data_buffer.has_value())
return -EFAULT;
return EFAULT;
timeval timestamp = { 0, 0 };
auto result = socket.recvfrom(*description, data_buffer.value(), iovs[0].iov_len, flags, user_addr, user_addr_length, timestamp);
if (flags & MSG_DONTWAIT)
@ -278,14 +278,14 @@ ssize_t Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user_msg, int
} else {
cmsg_timestamp = { { control_length, SOL_SOCKET, SCM_TIMESTAMP }, timestamp };
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))
return -EFAULT;
return EFAULT;
}
if (!copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_flags, &msg_flags))
return -EFAULT;
return EFAULT;
return result.value();
}
@ -295,17 +295,17 @@ int Process::get_sock_or_peer_name(const Params& params)
{
socklen_t addrlen_value;
if (!copy_from_user(&addrlen_value, params.addrlen, sizeof(socklen_t)))
return -EFAULT;
return EFAULT;
if (addrlen_value <= 0)
return -EINVAL;
return EINVAL;
auto description = file_description(params.sockfd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
@ -317,33 +317,33 @@ int Process::get_sock_or_peer_name(const Params& params)
else
socket.get_peer_address((sockaddr*)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))
return -EFAULT;
return EFAULT;
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;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
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;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
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;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
int sockfd = params.sockfd;
int level = params.level;
@ -353,30 +353,30 @@ int Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user
socklen_t value_size;
if (!copy_from_user(&value_size, params.value_size, sizeof(socklen_t)))
return -EFAULT;
return EFAULT;
auto description = file_description(sockfd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
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;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
Userspace<const void*> user_value((FlatPtr)params.value);
auto description = file_description(params.sockfd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_socket())
return -ENOTSOCK;
return ENOTSOCK;
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
return socket.setsockopt(params.level, params.option, user_value, params.value_size);

View file

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

View file

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

View file

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

View file

@ -34,31 +34,31 @@
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);
Syscall::SC_create_thread_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
unsigned detach_state = params.m_detach_state;
int schedule_priority = params.m_schedule_priority;
unsigned stack_size = params.m_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;
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
int requested_thread_priority = schedule_priority;
if (requested_thread_priority < THREAD_PRIORITY_MIN || requested_thread_priority > THREAD_PRIORITY_MAX)
return -EINVAL;
return EINVAL;
bool is_thread_joinable = (0 == detach_state);
@ -108,31 +108,31 @@ void Process::sys$exit_thread(Userspace<void*> exit_value)
VERIFY_NOT_REACHED();
}
int Process::sys$detach_thread(pid_t tid)
KResultOr<int> Process::sys$detach_thread(pid_t tid)
{
REQUIRE_PROMISE(thread);
auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid())
return -ESRCH;
return ESRCH;
if (!thread->is_joinable())
return -EINVAL;
return EINVAL;
thread->detach();
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);
auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid())
return -ESRCH;
return ESRCH;
auto current_thread = Thread::current();
if (thread == current_thread)
return -EDEADLK;
return EDEADLK;
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))
return -EFAULT;
return EFAULT;
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);
auto name = copy_string_from_user(user_name, user_name_length);
if (name.is_null())
return -EFAULT;
return EFAULT;
const size_t max_thread_name_size = 64;
if (name.length() > max_thread_name_size)
return -EINVAL;
return EINVAL;
auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid())
return -ESRCH;
return ESRCH;
thread->set_name(move(name));
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);
if (buffer_size == 0)
return -EINVAL;
return EINVAL;
auto thread = Thread::from_tid(tid);
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
auto thread_name = thread->name();
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))
return -EFAULT;
return EFAULT;
return 0;
}
int Process::sys$gettid()
KResultOr<int> Process::sys$gettid()
{
REQUIRE_PROMISE(stdio);
return Thread::current()->tid().value();

View file

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

View file

@ -31,36 +31,36 @@
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);
auto description = file_description(fd);
if (!description)
return -EBADF;
return EBADF;
if (!description->is_tty())
return -ENOTTY;
return ENOTTY;
auto tty_name = description->tty()->tty_name();
if (size < tty_name.length() + 1)
return -ERANGE;
return ERANGE;
if (!copy_to_user(buffer, tty_name.characters(), tty_name.length() + 1))
return -EFAULT;
return EFAULT;
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);
auto description = file_description(fd);
if (!description)
return -EBADF;
return EBADF;
auto* master_pty = description->master_pty();
if (!master_pty)
return -ENOTTY;
return ENOTTY;
auto pts_name = master_pty->pts_name();
if (size < pts_name.length() + 1)
return -ERANGE;
return ERANGE;
if (!copy_to_user(buffer, pts_name.characters(), pts_name.length() + 1))
return -EFAULT;
return EFAULT;
return 0;
}

View file

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

View file

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

View file

@ -30,7 +30,7 @@
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);
auto path = get_syscall_path_argument(user_path, path_length);

View file

@ -32,11 +32,11 @@
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;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
if (!params.path.characters && !params.permissions.characters) {
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)
return -EPERM;
return EPERM;
if (!params.path.characters || !params.permissions.characters)
return -EINVAL;
return EINVAL;
if (params.permissions.length > 5)
return -EINVAL;
return EINVAL;
auto path = get_syscall_path_argument(params.path);
if (path.is_error())
return path.error();
if (path.value().is_empty() || path.value().characters()[0] != '/')
return -EINVAL;
return EINVAL;
auto permissions = copy_string_from_user(params.permissions);
if (permissions.is_null())
return -EFAULT;
return EFAULT;
// Let's work out permissions first...
unsigned new_permissions = 0;
@ -83,7 +83,7 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
new_permissions |= UnveilAccess::Browse;
break;
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.
if (old_permissions != UnveilAccess::None || !matching_node.permissions_inherited_from_root()) {
if (new_permissions & ~old_permissions)
return -EPERM;
return EPERM;
}
matching_node.set_metadata({ matching_node.path(), (UnveilAccess)new_permissions, true, false });
return 0;

View file

@ -30,7 +30,7 @@
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);
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;
if (user_buf) {
if (!copy_from_user(&buf, user_buf))
return -EFAULT;
return EFAULT;
} else {
auto now = kgettimeofday();
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;
}
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);
Syscall::SC_waitid_params params;
if (!copy_from_user(&params, user_params))
return -EFAULT;
return EFAULT;
switch (params.idtype) {
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();
if (!copy_to_user(params.infop, &siginfo_or_error.value()))
return -EFAULT;
return EFAULT;
return 0;
}

View file

@ -31,7 +31,7 @@
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);
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();
if (!inode.fs().supports_watchers())
return -ENOTSUP;
return ENOTSUP;
int fd = alloc_fd();
if (fd < 0)

View file

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