Kernel/VFS: Add file owners and file modes, and check those in system calls

This commit is contained in:
apio 2022-10-28 17:10:28 +02:00
parent 6ddfc5ee52
commit 0115cce750
14 changed files with 158 additions and 4 deletions

View File

@ -1,6 +1,7 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
typedef long ssize_t;
@ -19,7 +20,7 @@ namespace VFS
typedef ssize_t (*node_read)(Node*, size_t, size_t, char*);
typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*);
typedef Node* (*node_finddir)(Node*, const char*);
typedef int (*node_mkdir)(Node*, const char*);
typedef int (*node_mkdir)(Node*, const char*, mode_t);
typedef int (*node_block)(Node*);
typedef Node* (*node_readdir)(Node*, long);
@ -38,6 +39,9 @@ namespace VFS
node_block block_func;
int tty = 0;
Node* link;
int uid;
int gid;
mode_t mode;
};
ssize_t read(Node* node, size_t offset, size_t length, char* buffer);
@ -45,6 +49,9 @@ namespace VFS
int mkdir(const char* path, const char* name);
int mkdir(const char* pathname);
int do_mkdir(const char* path, const char* name, int uid, int gid, mode_t mode);
int do_mkdir(const char* pathname, int uid, int gid, mode_t mode);
int would_block(Node* node);
void mount_root(Node* root);
@ -61,4 +68,11 @@ namespace VFS
Node* root();
Node* readdir(Node* dir, long offset);
bool can_execute(Node* node, int uid, int gid);
bool can_read(Node* node, int uid, int gid);
bool can_write(Node* node, int uid, int gid);
bool is_setuid(Node* node);
bool is_setgid(Node* node);
}

View File

@ -157,7 +157,43 @@ int VFS::mkdir(const char* path, const char* name)
kwarnln("Already exists");
return -EEXIST;
}
return node->mkdir_func(node, name);
return node->mkdir_func(node, name, 0755);
}
int VFS::do_mkdir(const char* path, const char* name, int uid, int gid, mode_t mode)
{
Node* node = resolve_path(path, vfs_root);
if (!node)
{
kwarnln("Attempting to mkdir in %s, which does not exist", path);
return -ENOENT;
}
if (node->type != VFS_DIRECTORY)
{
kwarnln("Attempting to mkdir in %s, which is not a directory!!", path);
return -ENOTDIR;
}
if (!node->mkdir_func)
{
kwarnln("Chosen node does not support mkdir()");
return -ENOTSUP;
}
if (!node->find_func)
{
kwarnln("Chosen node does not support finddir()");
return -ENOTSUP;
}
if (node->find_func(node, name) != nullptr)
{
kwarnln("Already exists");
return -EEXIST;
}
if (!can_write(node, uid, gid))
{
kwarnln("Not enough permissions");
return -EACCES;
}
return node->mkdir_func(node, name, mode);
}
int VFS::mkdir(const char* pathname)
@ -178,6 +214,24 @@ int VFS::mkdir(const char* pathname)
return result;
}
int VFS::do_mkdir(const char* pathname, int uid, int gid, mode_t mode)
{
char* bstr = strdup(pathname);
char* dstr = strdup(pathname);
char* base = basename(bstr);
char* dir = dirname(dstr);
kdbgln("mkdir(): creating %s in directory %s", base, dir);
int result = do_mkdir(dir, base, uid, gid, mode);
kfree(bstr);
kfree(dstr);
return result;
}
bool VFS::exists(const char* pathname)
{
return resolve_path(pathname) != nullptr;
@ -208,4 +262,35 @@ VFS::Node* VFS::readdir(VFS::Node* dir, long offset)
if (!dir) return 0;
if (!dir->readdir_func) return 0;
return dir->readdir_func(dir, offset);
}
bool VFS::can_execute(VFS::Node* node, int uid, int gid)
{
if (uid == node->uid) return node->mode & 0100;
if (gid == node->gid) return node->mode & 0010;
return node->mode & 0001;
}
bool VFS::can_write(VFS::Node* node, int uid, int gid)
{
if (uid == node->uid) return node->mode & 0200;
if (gid == node->gid) return node->mode & 0020;
return node->mode & 0002;
}
bool VFS::can_read(VFS::Node* node, int uid, int gid)
{
if (uid == node->uid) return node->mode & 0400;
if (gid == node->gid) return node->mode & 0040;
return node->mode & 0004;
}
bool VFS::is_setuid(VFS::Node* node)
{
return node->mode & 04000;
}
bool VFS::is_setgid(VFS::Node* node)
{
return node->mode & 02000;
}

View File

@ -14,6 +14,8 @@ VFS::Node* ConsoleDevice::create_new(const char* devname)
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->tty = 1;
dev->uid = dev->gid = 0;
dev->mode = 0222;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -25,6 +25,8 @@ VFS::Node* DeviceFS::get()
devfs_root->type = VFS_DIRECTORY;
devfs_root->find_func = DeviceFS::finddir;
devfs_root->readdir_func = DeviceFS::readdir;
devfs_root->mode = 0755;
devfs_root->uid = devfs_root->gid = 0;
strncpy(devfs_root->name, "dev", sizeof(devfs_root->name));
devfs_files[devfs_file_count++] = VersionDevice::create_new("version");

View File

@ -26,6 +26,8 @@ VFS::Node* KeyboardDevice::create_new(const char* devname)
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->tty = 1;
dev->uid = dev->gid = 0;
dev->mode = 0444;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -12,6 +12,8 @@ VFS::Node* NullDevice::create_new(const char* devname)
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0666;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -14,6 +14,8 @@ VFS::Node* RandomDevice::create_new(const char* devname)
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0444;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -13,6 +13,8 @@ VFS::Node* SerialDevice::create_new(const char* devname)
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0200;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -12,6 +12,8 @@ VFS::Node* UptimeDevice::create_new(const char* devname)
dev->length = 0;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0444;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -12,6 +12,8 @@ VFS::Node* VersionDevice::create_new(const char* devname)
dev->length = strlen(moon_version()) + 5;
dev->type = VFS_DEVICE;
dev->flags = 0;
dev->uid = dev->gid = 0;
dev->mode = 0444;
strncpy(dev->name, devname, sizeof(dev->name));
return dev;
}

View File

@ -225,6 +225,7 @@ int initrd_mkdir(VFS::Node* node, const char* name) // FIXME: Return proper erro
new_node.mkdir_func = initrd_mkdir;
new_node.length = 0;
new_node.type = VFS_DIRECTORY;
new_node.uid = new_node.gid = 0;
strncpy(new_node.name, name, sizeof(new_node.name));
InitRD::Directory dir;
strncpy(dir.name, name, sizeof(dir.name));
@ -282,6 +283,8 @@ static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode)
node.mkdir_func = initrd_mkdir;
node.readdir_func = initrd_read_dir;
node.length = 0;
node.mode = 0755;
node.uid = node.gid = 0;
strncpy(node.name, buffer, sizeof(node.name));
strncpy(dir.name, buffer, sizeof(dir.name));
@ -341,6 +344,8 @@ static bool initrd_register_file(InitRD::File& f, uint64_t inode)
node.read_func = initrd_read;
node.length = f.size;
node.type = VFS_FILE;
node.mode = 0555;
node.uid = node.gid = 0;
strncpy(node.name, buffer, sizeof(node.name));
strncpy(f.name, buffer, sizeof(f.name));
@ -383,6 +388,8 @@ static void initrd_initialize_root()
initrd_root.length = 0;
initrd_root.inode = 0;
initrd_root.type |= VFS_DIRECTORY;
initrd_root.mode = 0755;
initrd_root.uid = initrd_root.gid = 0;
InitRD::Directory& root = dirs[0];
total_dirs++;
strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name));

View File

@ -97,6 +97,13 @@ void sys_execv(Context* context, const char* pathname, char** argv)
return;
}
if (!VFS::can_execute(program, Scheduler::current_task()->euid, Scheduler::current_task()->egid))
{
kfree(kpathname);
context->rax = -EACCES;
return;
}
long memusage;
if ((memusage = ELFLoader::check_elf_image(program)) < 0)
{
@ -216,6 +223,9 @@ void sys_execv(Context* context, const char* pathname, char** argv)
ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly
// wrong.
if (VFS::is_setuid(program)) task->uid = program->uid;
if (VFS::is_setgid(program)) task->gid = program->gid;
strlcpy(task->name, kpathname, sizeof(task->name));
Scheduler::reset_task(task, image);

View File

@ -207,6 +207,24 @@ void sys_open(Context* context, const char* filename, int flags, mode_t) // FIXM
return;
}
if (can_read && !VFS::can_read(node, current_task->euid, current_task->egid))
{
kwarnln("open failed because process with uid %d and gid %d couldn't open file %s with mode %d for reading",
current_task->euid, current_task->egid, kfilename, node->mode);
kfree(kfilename);
context->rax = -EACCES;
return;
}
if (can_write && !VFS::can_write(node, current_task->euid, current_task->egid))
{
kwarnln("open failed because process with uid %d and gid %d couldn't open file %s with mode %d for writing",
current_task->euid, current_task->egid, kfilename, node->mode);
kfree(kfilename);
context->rax = -EACCES;
return;
}
bool able_to_block = (flags & OPEN_NONBLOCK) == 0;
bool close_on_exec = (flags & OPEN_CLOEXEC) > 0;
@ -304,7 +322,7 @@ void sys_close(Context* context, int fd)
return;
}
void sys_mkdir(Context* context, const char* filename)
void sys_mkdir(Context* context, const char* filename, mode_t mode)
{
char* kfilename = strdup_from_user(filename);
if (!kfilename)
@ -313,7 +331,9 @@ void sys_mkdir(Context* context, const char* filename)
return;
}
int rc = VFS::mkdir(kfilename);
Task* current_task = Scheduler::current_task();
int rc = VFS::do_mkdir(kfilename, current_task->euid, current_task->egid, mode);
kfree(kfilename);

View File

@ -115,6 +115,7 @@ void Scheduler::add_kernel_task(const char* taskname, void (*task)(void))
new_task->user_task = false;
new_task->id = free_pid++;
new_task->ppid = 0;
new_task->uid = new_task->euid = new_task->gid = new_task->egid = 0;
new_task->regs.rip = (uint64_t)task;
new_task->allocated_stack =
(uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK); // 16 KB is enough for everyone, right?
@ -159,6 +160,7 @@ long Scheduler::load_user_task(const char* filename)
memset(&new_task->regs, 0, sizeof(Context));
new_task->id = free_pid++;
new_task->ppid = 0;
new_task->uid = new_task->euid = new_task->gid = new_task->egid = 0;
if (!new_task->allocator.init())
{
delete new_task;