serenity/Kernel/Syscalls/mount.cpp
Liav A. 3692af528e Kernel: Move most of VirtualFileSystem code to be in a namespace
There's no point in constructing an object just for the sake of keeping
a state that can be touched by anything in the kernel code.

Let's reduce everything to be in a C++ namespace called with the
previous name "VirtualFileSystem" and keep a smaller textual-footprint
struct called "VirtualFileSystemDetails".

This change also cleans up old "friend class" statements that were no
longer needed, and move methods from the VirtualFileSystem code to more
appropriate places as well.
Please note that the method of locking all filesystems during shutdown
is removed, as in that place there's no meaning to actually locking all
filesystems because of running in kernel mode entirely.
2024-07-21 11:44:23 +02:00

158 lines
6.4 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/FixedStringBuffer.h>
#include <Kernel/FileSystem/Custody.h>
#include <Kernel/FileSystem/MountFile.h>
#include <Kernel/FileSystem/VirtualFileSystem.h>
#include <Kernel/Tasks/Process.h>
namespace Kernel {
ErrorOr<FlatPtr> Process::sys$copy_mount(Userspace<Syscall::SC_copy_mount_params const*> user_params)
{
VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::mount));
auto credentials = this->credentials();
if (!credentials->is_superuser())
return EPERM;
auto params = TRY(copy_typed_from_user(user_params));
// NOTE: If some userspace program uses MS_REMOUNT, return EINVAL to indicate that we never want this
// flag to appear in the mount table...
if (params.flags & MS_REMOUNT || params.flags & MS_BIND)
return Error::from_errno(EINVAL);
auto original_path = TRY(try_copy_kstring_from_user(params.original_path));
auto target_path = TRY(try_copy_kstring_from_user(params.target_path));
auto mount_original_context = TRY(context_for_mount_operation(params.original_vfs_root_context_id, original_path->view()));
auto mount_target_context = TRY(context_for_mount_operation(params.target_vfs_root_context_id, target_path->view()));
TRY(VirtualFileSystem::copy_mount(
mount_original_context.custody,
mount_target_context.vfs_root_context,
mount_target_context.custody,
params.flags));
return 0;
}
ErrorOr<FlatPtr> Process::sys$fsopen(Userspace<Syscall::SC_fsopen_params const*> user_params)
{
VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::mount));
auto credentials = this->credentials();
if (!credentials->is_superuser())
return Error::from_errno(EPERM);
auto params = TRY(copy_typed_from_user(user_params));
// NOTE: 16 characters should be enough for any fstype today and in the future.
auto fs_type_string = TRY(get_syscall_name_string_fixed_buffer<16>(params.fs_type));
// NOTE: If some userspace program uses MS_REMOUNT, return EINVAL to indicate that we never want this
// flag to appear in the mount table...
if (params.flags & MS_REMOUNT || params.flags & MS_BIND)
return Error::from_errno(EINVAL);
auto const* fs_type_initializer = TRY(VirtualFileSystem::find_filesystem_type_initializer(fs_type_string.representable_view()));
VERIFY(fs_type_initializer);
auto mount_file = TRY(MountFile::create(*fs_type_initializer, params.flags));
auto description = TRY(OpenFileDescription::try_create(move(mount_file)));
return m_fds.with_exclusive([&](auto& fds) -> ErrorOr<FlatPtr> {
auto new_fd = TRY(fds.allocate());
fds[new_fd.fd].set(move(description), FD_CLOEXEC);
return new_fd.fd;
});
}
ErrorOr<FlatPtr> Process::sys$fsmount(Userspace<Syscall::SC_fsmount_params const*> user_params)
{
VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::mount));
auto credentials = this->credentials();
if (!credentials->is_superuser())
return Error::from_errno(EPERM);
auto params = TRY(copy_typed_from_user(user_params));
auto mount_description = TRY(open_file_description(params.mount_fd));
if (!mount_description->is_mount_file())
return Error::from_errno(EINVAL);
RefPtr<OpenFileDescription> source_description = TRY(open_file_description_ignoring_negative(params.source_fd));
auto target = TRY(try_copy_kstring_from_user(params.target));
auto mount_target_context = TRY(context_for_mount_operation(params.vfs_root_context_id, target->view()));
auto flags = mount_description->mount_file()->mount_flags();
TRY(VirtualFileSystem::mount(mount_target_context.vfs_root_context, *mount_description->mount_file(), source_description.ptr(), mount_target_context.custody, flags));
return 0;
}
ErrorOr<FlatPtr> Process::sys$remount(Userspace<Syscall::SC_remount_params const*> user_params)
{
VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::mount));
auto credentials = this->credentials();
if (!credentials->is_superuser())
return EPERM;
auto params = TRY(copy_typed_from_user(user_params));
if (params.flags & MS_REMOUNT)
return EINVAL;
if (params.flags & MS_BIND)
return EINVAL;
auto target = TRY(try_copy_kstring_from_user(params.target));
auto current_vfs_root_context = Process::current().vfs_root_context();
auto mount_target_context = TRY(context_for_mount_operation(params.vfs_root_context_id, target->view()));
TRY(VirtualFileSystem::remount(mount_target_context.vfs_root_context, mount_target_context.custody, params.flags));
return 0;
}
ErrorOr<FlatPtr> Process::sys$bindmount(Userspace<Syscall::SC_bindmount_params const*> user_params)
{
VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::mount));
auto credentials = this->credentials();
if (!credentials->is_superuser())
return EPERM;
auto params = TRY(copy_typed_from_user(user_params));
if (params.flags & MS_REMOUNT)
return EINVAL;
if (params.flags & MS_BIND)
return EINVAL;
auto source_fd = params.source_fd;
auto target = TRY(try_copy_kstring_from_user(params.target));
auto mount_target_context = TRY(context_for_mount_operation(params.vfs_root_context_id, target->view()));
auto description = TRY(open_file_description(source_fd));
if (!description->custody()) {
// NOTE: We only support bind-mounting inodes, not arbitrary files.
return ENODEV;
}
TRY(VirtualFileSystem::bind_mount(mount_target_context.vfs_root_context, *description->custody(), mount_target_context.custody, params.flags));
return 0;
}
ErrorOr<FlatPtr> Process::sys$umount(Userspace<Syscall::SC_umount_params const*> user_params)
{
VERIFY_NO_PROCESS_BIG_LOCK(this);
auto credentials = this->credentials();
if (!credentials->is_superuser())
return EPERM;
TRY(require_promise(Pledge::mount));
auto params = TRY(copy_typed_from_user(user_params));
auto target = TRY(try_copy_kstring_from_user(params.target));
auto mount_target_context = TRY(context_for_mount_operation(params.vfs_root_context_id, target->view()));
TRY(VirtualFileSystem::unmount(mount_target_context.vfs_root_context, mount_target_context.custody));
return 0;
}
}