diff --git a/base-sysroot.tar.gz b/base-sysroot.tar.gz index 457c9904..dab00c6a 100644 Binary files a/base-sysroot.tar.gz and b/base-sysroot.tar.gz differ diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 795d0720..556f98ea 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -14,6 +14,7 @@ set(KERNEL_SOURCES kernel/APIC.cpp kernel/BootInfo.cpp kernel/CPUID.cpp + kernel/Credentials.cpp kernel/Debug.cpp kernel/Device/Device.cpp kernel/Device/FramebufferDevice.cpp diff --git a/kernel/include/kernel/Credentials.h b/kernel/include/kernel/Credentials.h index 09083753..83dfba4a 100644 --- a/kernel/include/kernel/Credentials.h +++ b/kernel/include/kernel/Credentials.h @@ -1,5 +1,7 @@ #pragma once +#include + #include namespace Kernel @@ -31,9 +33,17 @@ namespace Kernel bool is_superuser() const { return m_euid == 0; } + bool has_egid(gid_t) const; + + BAN::ErrorOr initialize_supplementary_groups(); + + private: + BAN::ErrorOr find_username() const; + private: uid_t m_ruid, m_euid, m_suid; gid_t m_rgid, m_egid, m_sgid; + BAN::Vector m_supplementary; }; } diff --git a/kernel/kernel/Credentials.cpp b/kernel/kernel/Credentials.cpp new file mode 100644 index 00000000..59ec1a4a --- /dev/null +++ b/kernel/kernel/Credentials.cpp @@ -0,0 +1,165 @@ +#include +#include + +#include +#include + +namespace Kernel +{ + + static id_t parse_id(BAN::StringView line) + { + id_t id = 0; + for (char c : line) + { + if (!isdigit(c)) + return -1; + id = (id * 10) + (c - '0'); + } + return id; + }; + + BAN::ErrorOr Credentials::find_username() const + { + auto inode = TRY(VirtualFileSystem::get().file_from_absolute_path(*this, "/etc/passwd"sv, O_RDONLY)).inode; + + BAN::String line; + off_t offset = 0; + uint8_t buffer[128]; + while (offset < inode->size()) + { + size_t nread = TRY(inode->read(offset, { buffer, sizeof(buffer) })); + + bool line_done = false; + for (size_t i = 0; i < nread; i++) + { + if (buffer[i] == '\n') + { + TRY(line.append({ (const char*)buffer, i })); + line_done = true; + offset += i + 1; + break; + } + } + if (!line_done) + { + offset += nread; + TRY(line.append({ (const char*)buffer, nread })); + continue; + } + + auto parts = TRY(line.sv().split(':', true)); + if (parts.size() == 7 && m_euid == parse_id(parts[2])) + { + BAN::String result; + TRY(result.append(parts[0])); + return result; + } + + line.clear(); + } + + auto parts = TRY(line.sv().split(':', true)); + if (parts.size() == 7 && m_euid == parse_id(parts[2])) + { + BAN::String result; + TRY(result.append(parts[0])); + return result; + } + + return BAN::Error::from_errno(EINVAL); + } + + BAN::ErrorOr Credentials::initialize_supplementary_groups() + { + m_supplementary.clear(); + + auto username = TRY(find_username()); + + auto file_or_error = VirtualFileSystem::get().file_from_absolute_path(*this, "/etc/group", O_RDONLY); + if (file_or_error.is_error()) + { + if (file_or_error.error().get_error_code() == ENOENT) + return {}; + return file_or_error.error(); + } + + auto inode = file_or_error.value().inode; + + BAN::String line; + off_t offset = 0; + uint8_t buffer[128]; + while (offset < inode->size()) + { + size_t nread = TRY(inode->read(offset, { buffer, sizeof(buffer) })); + + bool line_done = false; + for (size_t i = 0; i < nread; i++) + { + if (buffer[i] == '\n') + { + TRY(line.append({ (const char*)buffer, i })); + line_done = true; + offset += i + 1; + break; + } + } + if (!line_done) + { + offset += nread; + TRY(line.append({ (const char*)buffer, nread })); + continue; + } + + auto parts = TRY(line.sv().split(':', true)); + if (parts.size() != 4) + { + line.clear(); + continue; + } + + auto users = TRY(parts[3].split(',')); + for (auto user : users) + { + if (user != username) + continue; + if (gid_t gid = parse_id(parts[2]); gid != -1) + { + TRY(m_supplementary.push_back(gid)); + break; + } + } + + line.clear(); + } + + auto parts = TRY(line.sv().split(':', true)); + if (parts.size() == 4) + { + auto users = TRY(parts[3].split(',')); + for (auto user : users) + { + if (user != username) + continue; + if (gid_t gid = parse_id(parts[2]); gid != -1) + { + TRY(m_supplementary.push_back(gid)); + break; + } + } + } + + return {}; + } + + bool Credentials::has_egid(gid_t gid) const + { + if (m_egid == gid) + return true; + for (gid_t supplementary : m_supplementary) + if (gid == supplementary) + return true; + return false; + } + +} diff --git a/kernel/kernel/Device/FramebufferDevice.cpp b/kernel/kernel/Device/FramebufferDevice.cpp index 63c4bb53..af989c7a 100644 --- a/kernel/kernel/Device/FramebufferDevice.cpp +++ b/kernel/kernel/Device/FramebufferDevice.cpp @@ -22,7 +22,7 @@ namespace Kernel if (g_boot_info.framebuffer.bpp != 24 && g_boot_info.framebuffer.bpp != 32) return BAN::Error::from_errno(ENOTSUP); auto* device_ptr = new FramebufferDevice( - 0666, 0, 0, + 0660, 0, 900, DevFileSystem::get().get_next_dev(), g_boot_info.framebuffer.address, g_boot_info.framebuffer.width, diff --git a/kernel/kernel/FS/Inode.cpp b/kernel/kernel/FS/Inode.cpp index d162316c..9681d72b 100644 --- a/kernel/kernel/FS/Inode.cpp +++ b/kernel/kernel/FS/Inode.cpp @@ -17,7 +17,7 @@ namespace Kernel { } else if ((mode().mode & S_IRUSR) && credentials.euid() == uid()) { } - else if ((mode().mode & S_IRGRP) && credentials.egid() == gid()) + else if ((mode().mode & S_IRGRP) && credentials.has_egid(gid())) { } else { @@ -31,7 +31,7 @@ namespace Kernel { } else if ((mode().mode & S_IWUSR) && credentials.euid() == uid()) { } - else if ((mode().mode & S_IWGRP) && credentials.egid() == gid()) + else if ((mode().mode & S_IWGRP) && credentials.has_egid(gid())) { } else { @@ -45,7 +45,7 @@ namespace Kernel { } else if ((mode().mode & S_IXUSR) && credentials.euid() == uid()) { } - else if ((mode().mode & S_IXGRP) && credentials.egid() == gid()) + else if ((mode().mode & S_IXGRP) && credentials.has_egid(gid())) { } else { diff --git a/kernel/kernel/Input/PS2Controller.cpp b/kernel/kernel/Input/PS2Controller.cpp index cf8eaae4..6faa2593 100644 --- a/kernel/kernel/Input/PS2Controller.cpp +++ b/kernel/kernel/Input/PS2Controller.cpp @@ -69,7 +69,7 @@ namespace Kernel::Input static PS2Controller* s_instance = nullptr; PS2Device::PS2Device() - : CharacterDevice(0440, 0, 0) + : CharacterDevice(0440, 0, 901) , m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device())) { } diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index c2b9abc4..d5704ba6 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -116,6 +116,8 @@ namespace Kernel BAN::ErrorOr Process::create_userspace(const Credentials& credentials, BAN::StringView path) { auto* process = create_process(credentials, 0); + TRY(process->m_credentials.initialize_supplementary_groups()); + MUST(process->m_working_directory.push_back('/')); process->m_page_table = BAN::UniqPtr::adopt(MUST(PageTable::create_userspace())); @@ -1348,6 +1350,7 @@ namespace Kernel m_credentials.set_euid(uid); m_credentials.set_ruid(uid); m_credentials.set_suid(uid); + TRY(m_credentials.initialize_supplementary_groups()); return 0; } @@ -1356,6 +1359,7 @@ namespace Kernel if (uid == m_credentials.ruid() || uid == m_credentials.suid()) { m_credentials.set_euid(uid); + TRY(m_credentials.initialize_supplementary_groups()); return 0; } @@ -1402,6 +1406,7 @@ namespace Kernel if (uid == m_credentials.ruid() || uid == m_credentials.suid() || m_credentials.is_superuser()) { m_credentials.set_euid(uid); + TRY(m_credentials.initialize_supplementary_groups()); return 0; } @@ -1468,6 +1473,8 @@ namespace Kernel if (euid != -1) m_credentials.set_euid(euid); + TRY(m_credentials.initialize_supplementary_groups()); + return 0; }