kernel: Add process and filesystem UIDs and GIDs

This commit is contained in:
apio 2023-04-08 13:12:49 +02:00
parent 208fdd64ac
commit f6f9254eb4
Signed by: apio
GPG Key ID: B8A7D06E42258954
12 changed files with 165 additions and 32 deletions

View File

@ -4,6 +4,7 @@
#include "boot/bootboot.h" #include "boot/bootboot.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "thread/Thread.h"
#include <bits/modes.h> #include <bits/modes.h>
#include <luna/Alignment.h> #include <luna/Alignment.h>
@ -19,7 +20,7 @@ void InitRD::initialize()
static Result<void> vfs_create_dir_if_not_exists(const char* path, mode_t mode) static Result<void> vfs_create_dir_if_not_exists(const char* path, mode_t mode)
{ {
auto rc = VFS::create_directory(path); auto rc = VFS::create_directory(path, Credentials {});
if (rc.has_error()) if (rc.has_error())
{ {
if (rc.error() == EEXIST) return {}; if (rc.error() == EEXIST) return {};
@ -36,7 +37,7 @@ Result<void> InitRD::populate_vfs()
{ {
if (entry.type == TarStream::EntryType::RegularFile) if (entry.type == TarStream::EntryType::RegularFile)
{ {
auto file = TRY(VFS::create_file(entry.name)); auto file = TRY(VFS::create_file(entry.name, Credentials {}));
file->write(entry.data(), 0, entry.size); file->write(entry.data(), 0, entry.size);
file->chmod(entry.mode & (mode_t)~S_IFMT); file->chmod(entry.mode & (mode_t)~S_IFMT);
} }

View File

@ -1,5 +1,7 @@
#include "fs/VFS.h" #include "fs/VFS.h"
#include "Log.h" #include "Log.h"
#include "thread/Thread.h"
#include <bits/modes.h>
#include <luna/PathParser.h> #include <luna/PathParser.h>
namespace VFS namespace VFS
@ -11,7 +13,7 @@ namespace VFS
return *root_fs->root_inode(); return *root_fs->root_inode();
} }
Result<SharedPtr<Inode>> resolve_path(const char* path) Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth)
{ {
auto parser = TRY(PathParser::create(path)); auto parser = TRY(PathParser::create(path));
@ -20,17 +22,23 @@ namespace VFS
// FIXME: Properly handle relative paths. // FIXME: Properly handle relative paths.
const char* section; const char* section;
while (parser.next().try_set_value(section)) { current_inode = TRY(current_inode->find(section)); } while (parser.next().try_set_value(section))
{
if (!can_execute(current_inode, auth)) return err(EACCES);
current_inode = TRY(current_inode->find(section));
}
return current_inode; return current_inode;
} }
Result<SharedPtr<Inode>> create_directory(const char* path) Result<SharedPtr<Inode>> create_directory(const char* path, Credentials auth)
{ {
auto parser = TRY(PathParser::create(path)); auto parser = TRY(PathParser::create(path));
auto parent_path = TRY(parser.dirname()); auto parent_path = TRY(parser.dirname());
auto parent_inode = TRY(resolve_path(parent_path.chars())); auto parent_inode = TRY(resolve_path(parent_path.chars(), auth));
if (!can_write(parent_inode, auth)) return err(EACCES);
auto child_name = TRY(parser.basename()); auto child_name = TRY(parser.basename());
@ -39,12 +47,14 @@ namespace VFS
return parent_inode->create_subdirectory(child_name.chars()); return parent_inode->create_subdirectory(child_name.chars());
} }
Result<SharedPtr<Inode>> create_file(const char* path) Result<SharedPtr<Inode>> create_file(const char* path, Credentials auth)
{ {
auto parser = TRY(PathParser::create(path)); auto parser = TRY(PathParser::create(path));
auto parent_path = TRY(parser.dirname()); auto parent_path = TRY(parser.dirname());
auto parent_inode = TRY(resolve_path(parent_path.chars())); auto parent_inode = TRY(resolve_path(parent_path.chars(), auth));
if (!can_write(parent_inode, auth)) return err(EACCES);
auto child_name = TRY(parser.basename()); auto child_name = TRY(parser.basename());
@ -52,4 +62,28 @@ namespace VFS
return parent_inode->create_file(child_name.chars()); return parent_inode->create_file(child_name.chars());
} }
bool can_execute(SharedPtr<Inode> inode, Credentials auth)
{
if (inode->uid() == auth.euid) { return inode->mode() & S_IXUSR; }
if (inode->gid() == auth.egid) { return inode->mode() & S_IXGRP; }
return inode->mode() & S_IXOTH;
}
bool can_write(SharedPtr<Inode> inode, Credentials auth)
{
if (inode->uid() == auth.euid) { return inode->mode() & S_IWUSR; }
if (inode->gid() == auth.egid) { return inode->mode() & S_IWGRP; }
return inode->mode() & S_IWOTH;
}
bool can_read(SharedPtr<Inode> inode, Credentials auth)
{
if (inode->uid() == auth.euid) { return inode->mode() & S_IRUSR; }
if (inode->gid() == auth.egid) { return inode->mode() & S_IRGRP; }
return inode->mode() & S_IROTH;
}
} }

View File

@ -3,6 +3,8 @@
#include <luna/StaticString.h> #include <luna/StaticString.h>
#include <sys/types.h> #include <sys/types.h>
struct Credentials;
namespace VFS namespace VFS
{ {
enum class InodeType enum class InodeType
@ -46,13 +48,25 @@ namespace VFS
virtual bool blocking() const = 0; virtual bool blocking() const = 0;
// Metadata accessors // Metadata accessors
virtual usize size() = 0; virtual usize size() const = 0;
virtual mode_t mode() = 0; virtual mode_t mode() const = 0;
virtual u32 uid() const
{
return 0;
}
virtual u32 gid() const
{
return 0;
}
// Metadata changers // Metadata changers
virtual Result<void> chmod(mode_t mode) = 0; virtual Result<void> chmod(mode_t mode) = 0;
virtual Result<void> chown(u32 uid, u32 gid) = 0;
// Generic VFS-related methods // Generic VFS-related methods
virtual FileSystem& fs() const = 0; virtual FileSystem& fs() const = 0;
@ -156,10 +170,14 @@ namespace VFS
extern SharedPtr<FileSystem> root_fs; extern SharedPtr<FileSystem> root_fs;
Result<SharedPtr<Inode>> resolve_path(const char* path); Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth);
Result<SharedPtr<Inode>> create_directory(const char* path); Result<SharedPtr<Inode>> create_directory(const char* path, Credentials auth);
Result<SharedPtr<Inode>> create_file(const char* path); Result<SharedPtr<Inode>> create_file(const char* path, Credentials auth);
bool can_execute(SharedPtr<Inode> inode, Credentials auth);
bool can_read(SharedPtr<Inode> inode, Credentials auth);
bool can_write(SharedPtr<Inode> inode, Credentials auth);
Inode& root_inode(); Inode& root_inode();
} }

View File

@ -144,7 +144,7 @@ namespace TmpFS
return {}; return {};
} }
usize FileInode::size() usize FileInode::size() const
{ {
return m_data_buffer.size(); return m_data_buffer.size();
} }

View File

@ -66,19 +66,36 @@ namespace TmpFS
Result<void> truncate(usize size) override; Result<void> truncate(usize size) override;
usize size() override; usize size() const override;
mode_t mode() override mode_t mode() const override
{ {
return m_mode; return m_mode;
} }
u32 uid() const override
{
return m_uid;
}
u32 gid() const override
{
return m_gid;
}
Result<void> chmod(mode_t mode) override Result<void> chmod(mode_t mode) override
{ {
m_mode = mode; m_mode = mode;
return {}; return {};
} }
Result<void> chown(u32 uid, u32 gid) override
{
m_uid = uid;
m_gid = gid;
return {};
}
virtual ~FileInode() = default; virtual ~FileInode() = default;
private: private:
@ -86,6 +103,8 @@ namespace TmpFS
Buffer m_data_buffer; Buffer m_data_buffer;
usize m_inode_number; usize m_inode_number;
mode_t m_mode; mode_t m_mode;
u32 m_uid { 0 };
u32 m_gid { 0 };
}; };
class DeviceInode : public VFS::DeviceInode class DeviceInode : public VFS::DeviceInode
@ -139,22 +158,39 @@ namespace TmpFS
return m_device->blocking(); return m_device->blocking();
} }
usize size() override usize size() const override
{ {
return 0; return 0;
} }
mode_t mode() override mode_t mode() const override
{ {
return m_mode; return m_mode;
} }
u32 uid() const override
{
return m_uid;
}
u32 gid() const override
{
return m_gid;
}
Result<void> chmod(mode_t mode) override Result<void> chmod(mode_t mode) override
{ {
m_mode = mode; m_mode = mode;
return {}; return {};
} }
Result<void> chown(u32 uid, u32 gid) override
{
m_uid = uid;
m_gid = gid;
return {};
}
virtual ~DeviceInode() = default; virtual ~DeviceInode() = default;
private: private:
@ -162,6 +198,8 @@ namespace TmpFS
SharedPtr<Device> m_device; SharedPtr<Device> m_device;
usize m_inode_number; usize m_inode_number;
mode_t m_mode; mode_t m_mode;
u32 m_uid { 0 };
u32 m_gid { 0 };
}; };
class DirInode : public VFS::Inode class DirInode : public VFS::Inode
@ -207,22 +245,39 @@ namespace TmpFS
return false; return false;
} }
usize size() override usize size() const override
{ {
return 0; return 0;
} }
mode_t mode() override mode_t mode() const override
{ {
return m_mode; return m_mode;
} }
u32 uid() const override
{
return m_uid;
}
u32 gid() const override
{
return m_gid;
}
Result<void> chmod(mode_t mode) override Result<void> chmod(mode_t mode) override
{ {
m_mode = mode; m_mode = mode;
return {}; return {};
} }
Result<void> chown(u32 uid, u32 gid) override
{
m_uid = uid;
m_gid = gid;
return {};
}
VFS::FileSystem& fs() const override VFS::FileSystem& fs() const override
{ {
return *m_fs; return *m_fs;
@ -249,6 +304,8 @@ namespace TmpFS
VFS::FileSystem* m_fs; VFS::FileSystem* m_fs;
usize m_inode_number; usize m_inode_number;
mode_t m_mode; mode_t m_mode;
u32 m_uid { 0 };
u32 m_gid { 0 };
SharedPtr<VFS::Inode> m_self; SharedPtr<VFS::Inode> m_self;

View File

@ -54,7 +54,7 @@ Result<void> init()
TRY(DeviceRegistry::init()); TRY(DeviceRegistry::init());
InitRD::populate_vfs(); InitRD::populate_vfs();
auto init = TRY(VFS::resolve_path("/bin/init")); auto init = TRY(VFS::resolve_path("/bin/init", Credentials {}));
TRY(Scheduler::new_userspace_thread(init, "/bin/init")); TRY(Scheduler::new_userspace_thread(init, "/bin/init"));
Scheduler::new_kernel_thread(reap_thread, "[reap]").release_value(); Scheduler::new_kernel_thread(reap_thread, "[reap]").release_value();

View File

@ -37,17 +37,16 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
auto argv = TRY(copy_string_vector_from_userspace(args[1])); auto argv = TRY(copy_string_vector_from_userspace(args[1]));
auto envp = TRY(copy_string_vector_from_userspace(args[2])); auto envp = TRY(copy_string_vector_from_userspace(args[2]));
auto current = Scheduler::current();
// FIXME: Make sure argv & envp are not too big. // FIXME: Make sure argv & envp are not too big.
auto inode = TRY(VFS::resolve_path(path.chars())); auto inode = TRY(VFS::resolve_path(path.chars(), current->auth));
// Not executable if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
if ((inode->mode() & S_IXUSR) != S_IXUSR) return err(EACCES);
kinfoln("exec: attempting to replace current image with %s", path.chars()); kinfoln("exec: attempting to replace current image with %s", path.chars());
auto current = Scheduler::current();
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->directory); }); auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->directory); });
auto image = TRY(ThreadImage::try_load_from_elf(inode)); auto image = TRY(ThreadImage::try_load_from_elf(inode));
@ -111,6 +110,7 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
thread->parent_id = current->id; thread->parent_id = current->id;
thread->fp_data.save(); thread->fp_data.save();
thread->name = current->name; thread->name = current->name;
thread->auth = current->auth;
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; } for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }

View File

@ -2,16 +2,20 @@
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h"
Result<u64> sys_mkdir(Registers*, SyscallArgs args) Result<u64> sys_mkdir(Registers*, SyscallArgs args)
{ {
auto path = TRY(MemoryManager::strdup_from_user(args[0])); auto path = TRY(MemoryManager::strdup_from_user(args[0]));
mode_t mode = (mode_t)args[1]; mode_t mode = (mode_t)args[1];
Thread* current = Scheduler::current();
kinfoln("mkdir: attempting to create %s", path.chars()); kinfoln("mkdir: attempting to create %s", path.chars());
auto inode = TRY(VFS::create_directory(path.chars())); auto inode = TRY(VFS::create_directory(path.chars(), current->auth));
inode->chmod(mode); inode->chmod(mode);
inode->chown(current->auth.euid, current->auth.egid);
return 0; return 0;
} }

View File

@ -12,6 +12,8 @@ Result<u64> sys_mknod(Registers*, SyscallArgs args)
mode_t mode = (mode_t)args[1]; mode_t mode = (mode_t)args[1];
dev_t dev = (dev_t)args[2]; dev_t dev = (dev_t)args[2];
Thread* current = Scheduler::current();
u32 maj = luna_dev_major(dev); u32 maj = luna_dev_major(dev);
u32 min = luna_dev_minor(dev); u32 min = luna_dev_minor(dev);
@ -22,7 +24,8 @@ Result<u64> sys_mknod(Registers*, SyscallArgs args)
auto dirname = TRY(parser.dirname()); auto dirname = TRY(parser.dirname());
auto basename = TRY(parser.basename()); auto basename = TRY(parser.basename());
auto parent = TRY(VFS::resolve_path(dirname.chars())); auto parent = TRY(VFS::resolve_path(dirname.chars(), current->auth));
if (!VFS::can_write(parent, current->auth)) return err(EACCES);
auto inode = TRY(parent->fs().create_device_inode(maj, min)); auto inode = TRY(parent->fs().create_device_inode(maj, min));
TRY(parent->add_entry(inode, basename.chars())); TRY(parent->add_entry(inode, basename.chars()));

View File

@ -25,13 +25,14 @@ Result<u64> sys_open(Registers*, SyscallArgs args)
if ((flags & O_RDWR) == 0) { return err(EINVAL); } if ((flags & O_RDWR) == 0) { return err(EINVAL); }
int error; int error;
bool ok = VFS::resolve_path(path.chars()).try_set_value_or_error(inode, error); bool ok = VFS::resolve_path(path.chars(), current->auth).try_set_value_or_error(inode, error);
if (!ok) if (!ok)
{ {
if (error == ENOENT && (flags & O_CREAT)) if (error == ENOENT && (flags & O_CREAT))
{ {
inode = TRY(VFS::create_file(path.chars())); inode = TRY(VFS::create_file(path.chars(), current->auth));
inode->chmod(mode); inode->chmod(mode);
inode->chown(current->auth.euid, current->auth.egid);
} }
else else
return err(error); return err(error);
@ -40,8 +41,8 @@ Result<u64> sys_open(Registers*, SyscallArgs args)
return err(EEXIST); return err(EEXIST);
else else
{ {
if ((flags & O_RDONLY) && (inode->mode() & S_IRUSR) == 0) return err(EACCES); if ((flags & O_RDONLY) && !VFS::can_read(inode, current->auth)) return err(EACCES);
if ((flags & O_WRONLY) && (inode->mode() & S_IWUSR) == 0) return err(EACCES); if ((flags & O_WRONLY) && !VFS::can_write(inode, current->auth)) return err(EACCES);
} }
if (inode->type() != VFS::InodeType::Directory && (flags & O_DIRECTORY)) return err(ENOTDIR); if (inode->type() != VFS::InodeType::Directory && (flags & O_DIRECTORY)) return err(ENOTDIR);

View File

@ -72,6 +72,8 @@ namespace Scheduler
thread->is_kernel = true; thread->is_kernel = true;
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };
g_threads.append(thread); g_threads.append(thread);
kinfoln("Created kernel thread: id %lu with ip %#lx and sp %#lx", thread->id, thread->ip(), thread->sp()); kinfoln("Created kernel thread: id %lu with ip %#lx and sp %#lx", thread->id, thread->ip(), thread->sp());
@ -114,6 +116,7 @@ namespace Scheduler
thread->is_kernel = false; thread->is_kernel = false;
thread->name = name; thread->name = name;
thread->parent_id = 0; thread->parent_id = 0;
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };
Vector<String> args; Vector<String> args;
auto name_string = TRY(String::from_cstring(name)); auto name_string = TRY(String::from_cstring(name));

View File

@ -38,6 +38,16 @@ struct FileDescriptor
static constexpr int FD_MAX = 64; static constexpr int FD_MAX = 64;
struct Credentials
{
u32 uid { 0 };
u32 euid { 0 };
u32 suid { 0 };
u32 gid { 0 };
u32 egid { 0 };
u32 sgid { 0 };
};
struct Thread : public LinkedListNode<Thread> struct Thread : public LinkedListNode<Thread>
{ {
Registers regs; Registers regs;
@ -45,6 +55,8 @@ struct Thread : public LinkedListNode<Thread>
u64 id; u64 id;
u64 parent_id; u64 parent_id;
Credentials auth;
u64 ticks = 0; u64 ticks = 0;
u64 ticks_in_user = 0; u64 ticks_in_user = 0;
u64 ticks_in_kernel = 0; u64 ticks_in_kernel = 0;