mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-30 00:31:14 +00:00
Kernel: Make all syscall functions return KResultOr<T>
This makes it a lot easier to return errors since we no longer have to worry about negating EFOO errors and can just return them flat.
This commit is contained in:
parent
9af1e1a3bf
commit
ac71775de5
Notes:
sideshowbarker
2024-07-18 21:49:02 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/ac71775de5a
290
Kernel/Process.h
290
Kernel/Process.h
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
return EFAULT;
|
||||
auto path = get_syscall_path_argument(params.path);
|
||||
if (path.is_error())
|
||||
return path.error();
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(¶ms, 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!
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¶ms, 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(¶ms, 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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(¶ms, 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(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
return EFAULT;
|
||||
auto target = get_syscall_path_argument(params.target);
|
||||
if (target.is_error())
|
||||
return target.error();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(¶ms, 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();
|
||||
|
|
|
@ -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(¶ms, 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(¶ms, 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(¶ms, 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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
return EFAULT;
|
||||
auto result = handle_ptrace(params, *this);
|
||||
return result.is_error() ? result.error().error() : result.value();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(¶ms, 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();
|
||||
}
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
};
|
||||
|
|
|
@ -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(¶ms, 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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ¶m))
|
||||
return -EFAULT;
|
||||
return EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¶ms, 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(¶ms, 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(), ¶ms.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(¶ms.fds[0], fds_copy.data(), params.nfds * sizeof(pollfd)))
|
||||
return -EFAULT;
|
||||
return EFAULT;
|
||||
|
||||
return fds_with_revents;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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);
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
int Process::sys$sync()
|
||||
KResultOr<int> Process::sys$sync()
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
VFS::the().sync();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¶ms, 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();
|
||||
|
|
|
@ -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, ×))
|
||||
return -EFAULT;
|
||||
return EFAULT;
|
||||
|
||||
return TimeManagement::the().uptime_ms() & 0x7fffffff;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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(¶ms, 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue