mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:48:11 +00:00

Instead of getting credentials from Process::current(), we now require that they be provided as input to the various VFS functions. This ensures that an atomic set of credentials is used throughout an entire VFS operation.
141 lines
5.4 KiB
C++
141 lines
5.4 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <Kernel/FileSystem/Custody.h>
|
|
#include <Kernel/FileSystem/DevPtsFS.h>
|
|
#include <Kernel/FileSystem/DevTmpFS.h>
|
|
#include <Kernel/FileSystem/Ext2FileSystem.h>
|
|
#include <Kernel/FileSystem/ISO9660FileSystem.h>
|
|
#include <Kernel/FileSystem/Plan9FileSystem.h>
|
|
#include <Kernel/FileSystem/ProcFS.h>
|
|
#include <Kernel/FileSystem/SysFS.h>
|
|
#include <Kernel/FileSystem/TmpFS.h>
|
|
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
|
#include <Kernel/Process.h>
|
|
|
|
namespace Kernel {
|
|
|
|
struct FileSystemInitializer {
|
|
StringView short_name;
|
|
StringView name;
|
|
bool requires_open_file_description { false };
|
|
bool requires_block_device { false };
|
|
bool requires_seekable_file { false };
|
|
ErrorOr<NonnullLockRefPtr<FileSystem>> (*create_with_fd)(OpenFileDescription&) = nullptr;
|
|
ErrorOr<NonnullLockRefPtr<FileSystem>> (*create)(void) = nullptr;
|
|
};
|
|
|
|
static constexpr FileSystemInitializer s_initializers[] = {
|
|
{ "proc"sv, "ProcFS"sv, false, false, false, {}, ProcFS::try_create },
|
|
{ "devpts"sv, "DevPtsFS"sv, false, false, false, {}, DevPtsFS::try_create },
|
|
{ "dev"sv, "DevTmpFS"sv, false, false, false, {}, DevTmpFS::try_create },
|
|
{ "sys"sv, "SysFS"sv, false, false, false, {}, SysFS::try_create },
|
|
{ "tmp"sv, "TmpFS"sv, false, false, false, {}, TmpFS::try_create },
|
|
{ "ext2"sv, "Ext2FS"sv, true, true, true, Ext2FS::try_create, {} },
|
|
{ "9p"sv, "Plan9FS"sv, true, true, true, Plan9FS::try_create, {} },
|
|
{ "iso9660"sv, "ISO9660FS"sv, true, true, true, ISO9660FS::try_create, {} },
|
|
};
|
|
|
|
static ErrorOr<NonnullLockRefPtr<FileSystem>> create_filesystem_instance(StringView fs_type, OpenFileDescription* possible_description)
|
|
{
|
|
for (auto& initializer_entry : s_initializers) {
|
|
if (fs_type != initializer_entry.short_name && fs_type != initializer_entry.name)
|
|
continue;
|
|
if (!initializer_entry.requires_open_file_description) {
|
|
VERIFY(initializer_entry.create);
|
|
NonnullLockRefPtr<FileSystem> fs = TRY(initializer_entry.create());
|
|
return fs;
|
|
}
|
|
VERIFY(initializer_entry.create_with_fd);
|
|
if (!possible_description)
|
|
return EBADF;
|
|
OpenFileDescription& description = *possible_description;
|
|
|
|
if (initializer_entry.requires_block_device && !description.file().is_block_device())
|
|
return ENOTBLK;
|
|
if (initializer_entry.requires_seekable_file && !description.file().is_seekable()) {
|
|
dbgln("mount: this is not a seekable file");
|
|
return ENODEV;
|
|
}
|
|
NonnullLockRefPtr<FileSystem> fs = TRY(initializer_entry.create_with_fd(description));
|
|
return fs;
|
|
}
|
|
return ENODEV;
|
|
}
|
|
|
|
ErrorOr<FlatPtr> Process::sys$mount(Userspace<Syscall::SC_mount_params const*> user_params)
|
|
{
|
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
|
TRY(require_no_promises());
|
|
if (!is_superuser())
|
|
return EPERM;
|
|
|
|
auto params = TRY(copy_typed_from_user(user_params));
|
|
|
|
auto source_fd = params.source_fd;
|
|
auto target = TRY(try_copy_kstring_from_user(params.target));
|
|
auto fs_type_string = TRY(try_copy_kstring_from_user(params.fs_type));
|
|
auto fs_type = fs_type_string->view();
|
|
|
|
auto description_or_error = open_file_description(source_fd);
|
|
if (!description_or_error.is_error())
|
|
dbgln("mount {}: source fd {} @ {}", fs_type, source_fd, target);
|
|
else
|
|
dbgln("mount {} @ {}", fs_type, target);
|
|
|
|
auto target_custody = TRY(VirtualFileSystem::the().resolve_path(credentials(), target->view(), current_directory()));
|
|
|
|
if (params.flags & MS_REMOUNT) {
|
|
// We're not creating a new mount, we're updating an existing one!
|
|
TRY(VirtualFileSystem::the().remount(target_custody, params.flags & ~MS_REMOUNT));
|
|
return 0;
|
|
}
|
|
|
|
if (params.flags & MS_BIND) {
|
|
// We're doing a bind mount.
|
|
if (description_or_error.is_error())
|
|
return description_or_error.release_error();
|
|
auto description = description_or_error.release_value();
|
|
if (!description->custody()) {
|
|
// We only support bind-mounting inodes, not arbitrary files.
|
|
return ENODEV;
|
|
}
|
|
TRY(VirtualFileSystem::the().bind_mount(*description->custody(), target_custody, params.flags));
|
|
return 0;
|
|
}
|
|
|
|
LockRefPtr<FileSystem> fs;
|
|
|
|
if (!description_or_error.is_error()) {
|
|
auto description = description_or_error.release_value();
|
|
fs = TRY(create_filesystem_instance(fs_type, description.ptr()));
|
|
auto source_pseudo_path = TRY(description->pseudo_path());
|
|
dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target);
|
|
} else {
|
|
fs = TRY(create_filesystem_instance(fs_type, {}));
|
|
}
|
|
|
|
TRY(fs->initialize());
|
|
TRY(VirtualFileSystem::the().mount(*fs, target_custody, params.flags));
|
|
return 0;
|
|
}
|
|
|
|
ErrorOr<FlatPtr> Process::sys$umount(Userspace<char const*> user_mountpoint, size_t mountpoint_length)
|
|
{
|
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
|
if (!is_superuser())
|
|
return EPERM;
|
|
|
|
TRY(require_no_promises());
|
|
|
|
auto mountpoint = TRY(get_syscall_path_argument(user_mountpoint, mountpoint_length));
|
|
auto custody = TRY(VirtualFileSystem::the().resolve_path(credentials(), mountpoint->view(), current_directory()));
|
|
auto& guest_inode = custody->inode();
|
|
TRY(VirtualFileSystem::the().unmount(guest_inode));
|
|
return 0;
|
|
}
|
|
|
|
}
|