From c62e820bcf1a6ebe171e107996aadb3eaa4d13bc Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 11 Jun 2023 19:52:13 +0300 Subject: [PATCH] Kernel: Add basic Credentials for the system Now filesystem access/open, etc confirm that you have access for rwxs --- LibELF/LibELF/ELF.cpp | 10 ++-- LibELF/include/LibELF/ELF.h | 7 ++- kernel/CMakeLists.txt | 1 + kernel/include/kernel/Credentials.h | 40 +++++++++++++ kernel/include/kernel/FS/Inode.h | 3 + kernel/include/kernel/FS/VirtualFileSystem.h | 8 +-- kernel/include/kernel/Process.h | 11 ++-- kernel/include/kernel/Terminal/TTY.h | 3 +- kernel/kernel/FS/Inode.cpp | 59 ++++++++++++++++++++ kernel/kernel/FS/VirtualFileSystem.cpp | 37 ++++++------ kernel/kernel/Process.cpp | 37 ++++++------ kernel/kernel/kernel.cpp | 4 +- userspace/ls/main.cpp | 2 +- 13 files changed, 168 insertions(+), 54 deletions(-) create mode 100644 kernel/include/kernel/Credentials.h create mode 100644 kernel/kernel/FS/Inode.cpp diff --git a/LibELF/LibELF/ELF.cpp b/LibELF/LibELF/ELF.cpp index edc1e4d62..7751f4af2 100644 --- a/LibELF/LibELF/ELF.cpp +++ b/LibELF/LibELF/ELF.cpp @@ -21,12 +21,10 @@ namespace LibELF { #ifdef __is_kernel - BAN::ErrorOr> ELF::load_from_file(BAN::StringView file_path) + BAN::ErrorOr> ELF::load_from_file(BAN::RefPtr inode) { - auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(file_path, true)); - PageTable::current().lock(); - size_t page_count = BAN::Math::div_round_up(file.inode->size(), PAGE_SIZE); + size_t page_count = BAN::Math::div_round_up(inode->size(), PAGE_SIZE); vaddr_t vaddr = PageTable::current().get_free_contiguous_pages(page_count, (vaddr_t)g_kernel_end); auto virtual_range = BAN::UniqPtr::adopt( VirtualRange::create( @@ -37,9 +35,9 @@ namespace LibELF ); PageTable::current().unlock(); - TRY(file.inode->read(0, (void*)vaddr, file.inode->size())); + TRY(inode->read(0, (void*)vaddr, inode->size())); - ELF* elf_ptr = new ELF(BAN::move(virtual_range), file.inode->size()); + ELF* elf_ptr = new ELF(BAN::move(virtual_range), inode->size()); if (elf_ptr == nullptr) return BAN::Error::from_errno(ENOMEM); diff --git a/LibELF/include/LibELF/ELF.h b/LibELF/include/LibELF/ELF.h index 55ced9fdf..39faec2cd 100644 --- a/LibELF/include/LibELF/ELF.h +++ b/LibELF/include/LibELF/ELF.h @@ -1,6 +1,7 @@ #pragma once #ifdef __is_kernel +#include #include #endif @@ -16,8 +17,12 @@ namespace LibELF class ELF { public: +#ifdef __is_kernel + static BAN::ErrorOr> load_from_file(BAN::RefPtr); +#else static BAN::ErrorOr> load_from_file(BAN::StringView); - +#endif + const Elf64FileHeader& file_header64() const; const Elf64ProgramHeader& program_header64(size_t) const; const Elf64SectionHeader& section_header64(size_t) const; diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 26019ea20..c259333ac 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -19,6 +19,7 @@ set(KERNEL_SOURCES kernel/Errors.cpp kernel/Font.cpp kernel/FS/Ext2.cpp + kernel/FS/Inode.cpp kernel/FS/VirtualFileSystem.cpp kernel/Input/PS2Controller.cpp kernel/Input/PS2Keyboard.cpp diff --git a/kernel/include/kernel/Credentials.h b/kernel/include/kernel/Credentials.h new file mode 100644 index 000000000..984579da2 --- /dev/null +++ b/kernel/include/kernel/Credentials.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace Kernel +{ + + class Credentials + { + public: + Credentials(uid_t ruid, uid_t euid, gid_t rgid, gid_t egid) + : m_ruid(ruid), m_euid(euid), m_suid(0) + , m_rgid(rgid), m_egid(egid), m_sgid(0) + { } + + uid_t ruid() const { return m_ruid; } + uid_t euid() const { return m_euid; } + uid_t suid() const { return m_suid; } + + gid_t rgid() const { return m_rgid; } + gid_t egid() const { return m_egid; } + gid_t sgid() const { return m_sgid; } + + private: + uid_t m_ruid, m_euid, m_suid; + gid_t m_rgid, m_egid, m_sgid; + }; + +} + +namespace BAN::Formatter +{ + + template + void print_argument(F putc, const Kernel::Credentials& credentials, const ValueFormat&) + { + print(putc, "(ruid {}, euid {})", credentials.ruid(), credentials.euid()); + } + +} diff --git a/kernel/include/kernel/FS/Inode.h b/kernel/include/kernel/FS/Inode.h index 6ce30b75f..376d1b01d 100644 --- a/kernel/include/kernel/FS/Inode.h +++ b/kernel/include/kernel/FS/Inode.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -56,6 +57,8 @@ namespace Kernel public: virtual ~Inode() {} + bool can_access(const Credentials&, int); + bool operator==(const Inode& other) const { return dev() == other.dev() && rdev() == other.rdev() && ino() == other.ino(); } virtual ino_t ino() const = 0; diff --git a/kernel/include/kernel/FS/VirtualFileSystem.h b/kernel/include/kernel/FS/VirtualFileSystem.h index a97586e3b..ec83ec66d 100644 --- a/kernel/include/kernel/FS/VirtualFileSystem.h +++ b/kernel/include/kernel/FS/VirtualFileSystem.h @@ -11,21 +11,21 @@ namespace Kernel class VirtualFileSystem : public FileSystem { public: - static BAN::ErrorOr initialize(BAN::StringView); + static void initialize(BAN::StringView); static VirtualFileSystem& get(); virtual ~VirtualFileSystem() {}; virtual BAN::RefPtr root_inode() override { return m_root_fs->root_inode(); } - BAN::ErrorOr mount(BAN::StringView, BAN::StringView); - BAN::ErrorOr mount(FileSystem*, BAN::StringView); + BAN::ErrorOr mount(const Credentials&, BAN::StringView, BAN::StringView); + BAN::ErrorOr mount(const Credentials&, FileSystem*, BAN::StringView); struct File { BAN::RefPtr inode; BAN::String canonical_path; }; - BAN::ErrorOr file_from_absolute_path(BAN::StringView, bool follow_link); + BAN::ErrorOr file_from_absolute_path(const Credentials&, BAN::StringView, int); private: VirtualFileSystem() = default; diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 6430b2061..07e41f346 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,7 @@ namespace Kernel public: static Process* create_kernel(entry_t, void*); - static BAN::ErrorOr create_userspace(BAN::StringView); + static BAN::ErrorOr create_userspace(const Credentials&, BAN::StringView); ~Process(); [[noreturn]] void exit(int status); @@ -91,12 +92,12 @@ namespace Kernel const userspace_info_t& userspace_info() const { return m_userspace_info; } private: - Process(pid_t); - static Process* create_process(); + Process(const Credentials&, pid_t); + static Process* create_process(const Credentials&); static void register_process(Process*); // Load an elf file to virtual address space of the current page table - static BAN::ErrorOr> load_elf_for_exec(BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector& path_env); + static BAN::ErrorOr> load_elf_for_exec(const Credentials&, BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector& path_env); // Copy an elf file from the current page table to the processes own void load_elf_to_memory(LibELF::ELF&); @@ -125,6 +126,8 @@ namespace Kernel int waiting { 0 }; }; + Credentials m_credentials; + BAN::Vector m_open_files; BAN::Vector m_mapped_ranges; diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index 5886a23c8..0dfb6e6b4 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -108,7 +108,8 @@ namespace Kernel TerminalDriver* m_terminal_driver { nullptr }; public: - virtual Mode mode() const override { return { Mode::IFCHR | Mode::IRUSR }; } + // FIXME: these should be crw------- with the owner being user + virtual Mode mode() const override { return { Mode::IFCHR | Mode::IRUSR | Mode::IWUSR | Mode::IRGRP | Mode::IWGRP | Mode::IROTH | Mode::IWOTH }; } virtual uid_t uid() const override { return 0; } virtual gid_t gid() const override { return 0; } virtual dev_t rdev() const override { return m_rdev; } diff --git a/kernel/kernel/FS/Inode.cpp b/kernel/kernel/FS/Inode.cpp new file mode 100644 index 000000000..5d56e2897 --- /dev/null +++ b/kernel/kernel/FS/Inode.cpp @@ -0,0 +1,59 @@ +#include + +#include + +namespace Kernel +{ + + bool Inode::can_access(const Credentials& credentials, int flags) + { + if (credentials.euid() == 0) + return true; + + // We treat O_SEARCH as O_RDONLY + if (flags & (O_RDONLY | O_SEARCH)) + { + if (mode().mode & S_IROTH) + { } + else if ((mode().mode & S_IRUSR) && credentials.euid() == uid()) + { } + else if ((mode().mode & S_IRGRP) && credentials.egid() == gid()) + { } + else + { + return false; + } + } + + if (flags & O_WRONLY) + { + if (mode().mode & S_IWOTH) + { } + else if ((mode().mode & S_IWUSR) && credentials.euid() == uid()) + { } + else if ((mode().mode & S_IWGRP) && credentials.egid() == gid()) + { } + else + { + return false; + } + } + + if (flags & O_EXEC) + { + if (mode().mode & S_IXOTH) + { } + else if ((mode().mode & S_IXUSR) && credentials.euid() == uid()) + { } + else if ((mode().mode & S_IXGRP) && credentials.egid() == gid()) + { } + else + { + return false; + } + } + + return true; + } + +} \ No newline at end of file diff --git a/kernel/kernel/FS/VirtualFileSystem.cpp b/kernel/kernel/FS/VirtualFileSystem.cpp index 304a6a521..ceb1a2755 100644 --- a/kernel/kernel/FS/VirtualFileSystem.cpp +++ b/kernel/kernel/FS/VirtualFileSystem.cpp @@ -4,32 +4,27 @@ #include #include #include +#include namespace Kernel { static VirtualFileSystem* s_instance = nullptr; - BAN::ErrorOr VirtualFileSystem::initialize(BAN::StringView root) + void VirtualFileSystem::initialize(BAN::StringView root) { ASSERT(s_instance == nullptr); s_instance = new VirtualFileSystem(); - if (s_instance == nullptr) - return BAN::Error::from_errno(ENOMEM); - BAN::ScopeGuard guard([] { delete s_instance; s_instance = nullptr; } ); + ASSERT(s_instance); ASSERT(root.size() >= 5 && root.substring(0, 5) == "/dev/"sv);; root = root.substring(5); - auto partition_inode = TRY(DeviceManager::get().read_directory_inode(root)); - s_instance->m_root_fs = TRY(Ext2FS::create(*(Partition*)partition_inode.ptr())); + auto partition_inode = MUST(DeviceManager::get().read_directory_inode(root)); + s_instance->m_root_fs = MUST(Ext2FS::create(*(Partition*)partition_inode.ptr())); DeviceManager::get().set_blksize(s_instance->m_root_fs->root_inode()->blksize()); - TRY(s_instance->mount(&DeviceManager::get(), "/dev")); - - guard.disable(); - - return {}; + MUST(s_instance->mount({ 0, 0, 0, 0 }, &DeviceManager::get(), "/dev")); } VirtualFileSystem& VirtualFileSystem::get() @@ -38,9 +33,9 @@ namespace Kernel return *s_instance; } - BAN::ErrorOr VirtualFileSystem::mount(BAN::StringView partition, BAN::StringView target) + BAN::ErrorOr VirtualFileSystem::mount(const Credentials& credentials, BAN::StringView partition, BAN::StringView target) { - auto partition_file = TRY(file_from_absolute_path(partition, true)); + auto partition_file = TRY(file_from_absolute_path(credentials, partition, true)); if (!partition_file.inode->is_device()) return BAN::Error::from_errno(ENOTBLK); @@ -49,12 +44,12 @@ namespace Kernel return BAN::Error::from_errno(ENOTBLK); auto* file_system = TRY(Ext2FS::create(*(Partition*)device)); - return mount(file_system, target); + return mount(credentials, file_system, target); } - BAN::ErrorOr VirtualFileSystem::mount(FileSystem* file_system, BAN::StringView path) + BAN::ErrorOr VirtualFileSystem::mount(const Credentials& credentials, FileSystem* file_system, BAN::StringView path) { - auto file = TRY(file_from_absolute_path(path, true)); + auto file = TRY(file_from_absolute_path(credentials, path, true)); if (!file.inode->mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); @@ -82,7 +77,7 @@ namespace Kernel return nullptr; } - BAN::ErrorOr VirtualFileSystem::file_from_absolute_path(BAN::StringView path, bool follow_link) + BAN::ErrorOr VirtualFileSystem::file_from_absolute_path(const Credentials& credentials, BAN::StringView path, int flags) { LockGuard _(m_lock); @@ -129,6 +124,9 @@ namespace Kernel } else { + if (!inode->can_access(credentials, O_RDONLY)) + return BAN::Error::from_errno(EACCES); + inode = TRY(inode->read_directory_inode(path_part)); if (auto* mount_point = mount_from_host_inode(inode)) @@ -140,7 +138,7 @@ namespace Kernel path_parts.pop_back(); - if (inode->mode().iflnk() && (follow_link || !path_parts.empty())) + if (inode->mode().iflnk() && (!(flags & O_NOFOLLOW) || !path_parts.empty())) { auto target = TRY(inode->link_target()); if (target.empty()) @@ -174,6 +172,9 @@ namespace Kernel } } + if (!inode->can_access(credentials, flags)) + return BAN::Error::from_errno(EACCES); + if (canonical_path.empty()) TRY(canonical_path.push_back('/')); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 9bab81249..6b38f13b8 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -18,10 +18,10 @@ namespace Kernel static BAN::Vector s_processes; static SpinLock s_process_lock; - Process* Process::create_process() + Process* Process::create_process(const Credentials& credentials) { static pid_t s_next_pid = 1; - auto* process = new Process(s_next_pid++); + auto* process = new Process(credentials, s_next_pid++); ASSERT(process); return process; } @@ -37,7 +37,7 @@ namespace Kernel Process* Process::create_kernel(entry_t entry, void* data) { - auto* process = create_process(); + auto* process = create_process({ 0, 0, 0, 0 }); MUST(process->m_working_directory.push_back('/')); auto* thread = MUST(Thread::create_kernel(entry, data, process)); process->add_thread(thread); @@ -45,11 +45,11 @@ namespace Kernel return process; } - BAN::ErrorOr Process::create_userspace(BAN::StringView path) + BAN::ErrorOr Process::create_userspace(const Credentials& credentials, BAN::StringView path) { - auto elf = TRY(load_elf_for_exec(path, "/"sv, {})); + auto elf = TRY(load_elf_for_exec(credentials, path, "/"sv, {})); - auto* process = create_process(); + auto* process = create_process(credentials); MUST(process->m_working_directory.push_back('/')); process->m_page_table = BAN::UniqPtr::adopt(MUST(PageTable::create_userspace()));; @@ -89,8 +89,9 @@ namespace Kernel return process; } - Process::Process(pid_t pid) - : m_pid(pid) + Process::Process(const Credentials& credentials, pid_t pid) + : m_credentials(credentials) + , m_pid(pid) , m_tty(TTY::current()) { } @@ -167,7 +168,7 @@ namespace Kernel return {}; } - BAN::ErrorOr> Process::load_elf_for_exec(BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector& path_env) + BAN::ErrorOr> Process::load_elf_for_exec(const Credentials& credentials, BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector& path_env) { if (file_path.empty()) return BAN::Error::from_errno(ENOENT); @@ -204,7 +205,7 @@ namespace Kernel TRY(absolute_path.push_back('/')); TRY(absolute_path.append(file_path)); - if (!VirtualFileSystem::get().file_from_absolute_path(absolute_path, true).is_error()) + if (!VirtualFileSystem::get().file_from_absolute_path(credentials, absolute_path, O_EXEC).is_error()) break; absolute_path.clear(); @@ -214,7 +215,9 @@ namespace Kernel return BAN::Error::from_errno(ENOENT); } - auto elf_or_error = LibELF::ELF::load_from_file(absolute_path); + auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(credentials, absolute_path, O_EXEC)); + + auto elf_or_error = LibELF::ELF::load_from_file(file.inode); if (elf_or_error.is_error()) { if (elf_or_error.error().get_error_code() == EINVAL) @@ -240,7 +243,7 @@ namespace Kernel BAN::ErrorOr Process::fork(uintptr_t rsp, uintptr_t rip) { - Process* forked = create_process(); + Process* forked = create_process(m_credentials); forked->m_page_table = BAN::UniqPtr::adopt(MUST(PageTable::create_userspace())); @@ -286,7 +289,7 @@ namespace Kernel path_env = TRY(BAN::StringView(envp[i]).substring(5).split(':')); } - auto elf = TRY(load_elf_for_exec(path, TRY(working_directory()), path_env)); + auto elf = TRY(load_elf_for_exec(m_credentials, path, TRY(working_directory()), path_env)); LockGuard lock_guard(m_lock); @@ -456,7 +459,7 @@ namespace Kernel BAN::String absolute_path = TRY(absolute_path_of(path)); - auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path, !(flags & O_NOFOLLOW))); + auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)); LockGuard _(m_lock); int fd = TRY(get_free_fd()); @@ -592,7 +595,7 @@ namespace Kernel auto directory = absolute_path.sv().substring(0, index); auto file_name = absolute_path.sv().substring(index); - auto parent_file = TRY(VirtualFileSystem::get().file_from_absolute_path(directory, true)); + auto parent_file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, directory, O_WRONLY)); TRY(parent_file.inode->create_file(file_name, mode)); return {}; @@ -606,7 +609,7 @@ namespace Kernel absolute_source = TRY(absolute_path_of(source)); absolute_target = TRY(absolute_path_of(target)); } - TRY(VirtualFileSystem::get().mount(absolute_source, absolute_target)); + TRY(VirtualFileSystem::get().mount(m_credentials, absolute_source, absolute_target)); return {}; } @@ -680,7 +683,7 @@ namespace Kernel { BAN::String absolute_path = TRY(absolute_path_of(path)); - auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path, true)); + auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_SEARCH)); if (!file.inode->mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index eb264f679..bdf6bae51 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -173,14 +173,14 @@ static void init2(void* tty1) DeviceManager::get().initialize_pci_devices(); DeviceManager::get().initialize_updater(); - MUST(VirtualFileSystem::initialize(cmdline.root)); + VirtualFileSystem::initialize(cmdline.root); if (auto res = PS2Controller::initialize(); res.is_error()) dprintln("{}", res.error()); ((TTY*)tty1)->initialize_device(); - MUST(Process::create_userspace("/usr/bin/Shell"sv)); + MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/Shell"sv)); return; Process::create_kernel( diff --git a/userspace/ls/main.cpp b/userspace/ls/main.cpp index db113e6d5..ccc6e810c 100644 --- a/userspace/ls/main.cpp +++ b/userspace/ls/main.cpp @@ -58,7 +58,7 @@ void list_directory(const char* path) } else { - printf("%s %d %s", mode_string(st.st_mode), st.st_size, dirent->d_name); + printf("%s %6d %s", mode_string(st.st_mode), st.st_size, dirent->d_name); } } else