diff options
-rw-r--r-- | Kernel/FileSystem/VirtualFileSystem.cpp | 14 | ||||
-rw-r--r-- | Kernel/Process.cpp | 36 | ||||
-rw-r--r-- | Kernel/Process.h | 5 | ||||
-rw-r--r-- | Kernel/Syscall.h | 3 | ||||
-rw-r--r-- | Kernel/init.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibC/unistd.cpp | 10 | ||||
-rw-r--r-- | Libraries/LibC/unistd.h | 1 |
7 files changed, 63 insertions, 8 deletions
diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 28276e655d..076cbba691 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -52,7 +52,7 @@ KResult VFS::mount(NonnullRefPtr<FS>&& file_system, Custody& mount_point) KResult VFS::mount(NonnullRefPtr<FS>&& file_system, StringView path) { LOCKER(m_lock); - auto result = resolve_path(path, root_custody()); + auto result = resolve_path(path, current->process().root_directory()); if (result.is_error()) { dbg() << "VFS: mount can't resolve mount point '" << path << "'"; return result.error(); @@ -667,11 +667,13 @@ KResultOr<NonnullRefPtr<Custody>> VFS::resolve_path(StringView path, Custody& ba auto parts = path.split_view('/', true); InodeIdentifier crumb_id; + auto& current_root = current->process().root_directory(); + NonnullRefPtrVector<Custody, 32> custody_chain; if (path[0] == '/') { - custody_chain.append(root_custody()); - crumb_id = root_inode_id(); + custody_chain.append(current_root); + crumb_id = current_root.inode().identifier(); } else { for (auto* custody = &base; custody; custody = custody->parent()) { // FIXME: Prepending here is not efficient! Fix this. @@ -684,7 +686,7 @@ KResultOr<NonnullRefPtr<Custody>> VFS::resolve_path(StringView path, Custody& ba *parent_custody = custody_chain.last(); for (int i = 0; i < parts.size(); ++i) { - bool inode_was_root_at_head_of_loop = crumb_id.is_root_inode(); + bool inode_was_root_at_head_of_loop = current_root.inode().identifier() == crumb_id; auto crumb_inode = get_inode(crumb_id); if (!crumb_inode) return KResult(-EIO); @@ -715,7 +717,7 @@ KResultOr<NonnullRefPtr<Custody>> VFS::resolve_path(StringView path, Custody& ba } if (auto mount = find_mount_for_host(crumb_id)) crumb_id = mount->guest(); - if (inode_was_root_at_head_of_loop && crumb_id.is_root_inode() && !is_vfs_root(crumb_id) && part == "..") { + if (inode_was_root_at_head_of_loop && crumb_id.is_root_inode() && crumb_id != current_root.inode().identifier() && part == "..") { auto mount = find_mount_for_guest(crumb_id); auto dir_inode = get_inode(mount->host()); ASSERT(dir_inode); @@ -724,7 +726,7 @@ KResultOr<NonnullRefPtr<Custody>> VFS::resolve_path(StringView path, Custody& ba crumb_inode = get_inode(crumb_id); ASSERT(crumb_inode); - custody_chain.append(Custody::get_or_create(&custody_chain.last(), part, *crumb_inode)); + custody_chain.append(Custody::create(&custody_chain.last(), part, *crumb_inode)); metadata = crumb_inode->metadata(); if (metadata.is_directory()) { diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 971ad69b04..3e95de39c3 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -565,6 +565,7 @@ pid_t Process::sys$fork(RegisterDump& regs) { Thread* child_first_thread = nullptr; auto* child = new Process(child_first_thread, m_name, m_uid, m_gid, m_pid, m_ring, m_cwd, m_executable, m_tty, this); + child->m_root_directory = m_root_directory; #ifdef FORK_DEBUG dbgprintf("fork: child=%p\n", child); @@ -966,15 +967,21 @@ Process* Process::create_user_process(Thread*& first_thread, const String& path, arguments.append(parts.last()); } RefPtr<Custody> cwd; + RefPtr<Custody> root; { InterruptDisabler disabler; - if (auto* parent = Process::from_pid(parent_pid)) + if (auto* parent = Process::from_pid(parent_pid)) { cwd = parent->m_cwd; + root = parent->m_root_directory; + } } if (!cwd) cwd = VFS::the().root_custody(); + if (!root) + root = VFS::the().root_custody(); + auto* process = new Process(first_thread, parts.take_last(), uid, gid, parent_pid, Ring3, move(cwd), nullptr, tty); error = process->exec(path, move(arguments), move(environment)); @@ -2650,6 +2657,7 @@ void Process::finalize() m_tty = nullptr; m_executable = nullptr; m_cwd = nullptr; + m_root_directory = nullptr; m_elf_loader = nullptr; disown_all_shared_buffers(); @@ -4127,3 +4135,29 @@ int Process::sys$set_process_boost(pid_t pid, int amount) process->m_priority_boost = amount; return 0; } + +int Process::sys$chroot(const char* user_path, size_t path_length) +{ + if (!is_superuser()) + return -EPERM; + auto path = get_syscall_path_argument(user_path, path_length); + if (path.is_error()) + return path.error(); + auto directory_or_error = VFS::the().open_directory(path.value(), current_directory()); + if (directory_or_error.is_error()) + return directory_or_error.error(); + set_root_directory(Custody::create(nullptr, "", directory_or_error.value()->inode())); + return 0; +} + +Custody& Process::root_directory() +{ + if (!m_root_directory) + m_root_directory = VFS::the().root_custody(); + return *m_root_directory; +} + +void Process::set_root_directory(const Custody& root) +{ + m_root_directory = root; +} diff --git a/Kernel/Process.h b/Kernel/Process.h index f1995de0aa..d76c4bd551 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -229,6 +229,7 @@ public: int sys$futex(const Syscall::SC_futex_params*); int sys$set_thread_boost(int tid, int amount); int sys$set_process_boost(pid_t, int amount); + int sys$chroot(const char* path, size_t path_length); static void initialize(); @@ -309,6 +310,9 @@ public: u32 priority_boost() const { return m_priority_boost; } + Custody& root_directory(); + void set_root_directory(const Custody&); + private: friend class MemoryManager; friend class Scheduler; @@ -369,6 +373,7 @@ private: RefPtr<Custody> m_executable; RefPtr<Custody> m_cwd; + RefPtr<Custody> m_root_directory; RefPtr<TTY> m_tty; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index d267b568d2..6cdf3d31bd 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -147,7 +147,8 @@ typedef u32 socklen_t; __ENUMERATE_SYSCALL(get_kernel_info_page) \ __ENUMERATE_SYSCALL(futex) \ __ENUMERATE_SYSCALL(set_thread_boost) \ - __ENUMERATE_SYSCALL(set_process_boost) + __ENUMERATE_SYSCALL(set_process_boost) \ + __ENUMERATE_SYSCALL(chroot) namespace Syscall { diff --git a/Kernel/init.cpp b/Kernel/init.cpp index b7df3d8691..8022facf29 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -145,6 +145,8 @@ VFS* vfs; hang(); } + current->process().set_root_directory(vfs->root_custody()); + dbgprintf("Load ksyms\n"); load_ksyms(); dbgprintf("Loaded ksyms\n"); diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index da27a3b0e9..2feb69c16f 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -617,4 +617,14 @@ int get_process_name(char* buffer, int buffer_size) int rc = syscall(SC_get_process_name, buffer, buffer_size); __RETURN_WITH_ERRNO(rc, rc, -1); } + +int chroot(const char* path) +{ + if (!path) { + errno = EFAULT; + return -1; + } + int rc = syscall(SC_chroot, path, strlen(path)); + __RETURN_WITH_ERRNO(rc, rc, -1); +} } diff --git a/Libraries/LibC/unistd.h b/Libraries/LibC/unistd.h index ccc1b43eda..fb5b6d09bd 100644 --- a/Libraries/LibC/unistd.h +++ b/Libraries/LibC/unistd.h @@ -51,6 +51,7 @@ int execvpe(const char* filename, char* const argv[], char* const envp[]); int execvp(const char* filename, char* const argv[]); int execl(const char* filename, const char* arg, ...); int execlp(const char* filename, const char* arg, ...); +int chroot(const char* path); void sync(); void _exit(int status); pid_t getsid(pid_t); |