Kernel/VFS: Add file owners and file modes, and check those in system calls
This commit is contained in:
parent
6ddfc5ee52
commit
0115cce750
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user