2020-07-31 01:01:41 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-07-31 01:01:41 +02:00
|
|
|
*/
|
|
|
|
|
2020-07-30 23:38:15 +02:00
|
|
|
#include <Kernel/FileSystem/Custody.h>
|
2022-10-24 10:38:41 +03:00
|
|
|
#include <Kernel/FileSystem/DevPtsFS/FileSystem.h>
|
2022-10-24 10:02:37 +03:00
|
|
|
#include <Kernel/FileSystem/Ext2FS/FileSystem.h>
|
2022-10-24 08:25:16 +03:00
|
|
|
#include <Kernel/FileSystem/FATFS/FileSystem.h>
|
2022-10-24 11:02:50 +03:00
|
|
|
#include <Kernel/FileSystem/ISO9660FS/FileSystem.h>
|
2022-10-24 10:28:24 +03:00
|
|
|
#include <Kernel/FileSystem/Plan9FS/FileSystem.h>
|
2022-10-24 09:41:31 +03:00
|
|
|
#include <Kernel/FileSystem/ProcFS/FileSystem.h>
|
2022-10-23 21:51:56 +03:00
|
|
|
#include <Kernel/FileSystem/SysFS/FileSystem.h>
|
2022-10-23 22:01:40 +03:00
|
|
|
#include <Kernel/FileSystem/TmpFS/FileSystem.h>
|
2020-07-30 23:38:15 +02:00
|
|
|
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
|
|
|
#include <Kernel/Process.h>
|
|
|
|
|
|
|
|
namespace Kernel {
|
|
|
|
|
2022-05-28 15:42:03 +03:00
|
|
|
struct FileSystemInitializer {
|
|
|
|
StringView short_name;
|
|
|
|
StringView name;
|
|
|
|
bool requires_open_file_description { false };
|
|
|
|
bool requires_block_device { false };
|
|
|
|
bool requires_seekable_file { false };
|
2022-08-19 20:53:40 +02:00
|
|
|
ErrorOr<NonnullLockRefPtr<FileSystem>> (*create_with_fd)(OpenFileDescription&) = nullptr;
|
|
|
|
ErrorOr<NonnullLockRefPtr<FileSystem>> (*create)(void) = nullptr;
|
2022-05-28 15:42:03 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
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 },
|
|
|
|
{ "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, {} },
|
2022-09-18 18:21:10 +02:00
|
|
|
{ "fat"sv, "FATFS"sv, true, true, true, FATFS::try_create, {} },
|
2022-05-28 15:42:03 +03:00
|
|
|
};
|
|
|
|
|
2022-08-20 00:03:24 +03:00
|
|
|
static ErrorOr<NonnullLockRefPtr<FileSystem>> find_or_create_filesystem_instance(StringView fs_type, OpenFileDescription* possible_description)
|
Kernel: Simplify mount syscall flow for regular calls
We do this by putting a distinction between two types of filesystems -
the first type is backed in RAM, and includes TmpFS, ProcFS, SysFS,
DevPtsFS and DevTmpFS. Because these filesystems are backed in RAM,
trying to mount them doesn't require source open file description.
The second type is filesystems that are backed by a file, therefore the
userspace program has to open them (hence it has a open file description
on them) and provide the appropriate source open file description.
By putting this distinction, we can early check if the user tried to
mount the second type of filesystems without a valid file description,
and fail with EBADF then.
Otherwise, we can proceed to either mount either type of filesystem,
provided that the fs_type is valid.
2022-05-28 14:52:48 +03:00
|
|
|
{
|
2022-05-28 15:42:03 +03:00
|
|
|
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);
|
2022-08-19 20:53:40 +02:00
|
|
|
NonnullLockRefPtr<FileSystem> fs = TRY(initializer_entry.create());
|
2022-05-28 15:42:03 +03:00
|
|
|
return fs;
|
|
|
|
}
|
2022-08-20 00:03:24 +03:00
|
|
|
// Note: If there's an associated file description with the filesystem, we could
|
|
|
|
// try to first find it from the VirtualFileSystem filesystem list and if it was not found,
|
|
|
|
// then create it and add it.
|
2022-05-28 15:42:03 +03:00
|
|
|
VERIFY(initializer_entry.create_with_fd);
|
|
|
|
if (!possible_description)
|
|
|
|
return EBADF;
|
|
|
|
OpenFileDescription& description = *possible_description;
|
Kernel: Simplify mount syscall flow for regular calls
We do this by putting a distinction between two types of filesystems -
the first type is backed in RAM, and includes TmpFS, ProcFS, SysFS,
DevPtsFS and DevTmpFS. Because these filesystems are backed in RAM,
trying to mount them doesn't require source open file description.
The second type is filesystems that are backed by a file, therefore the
userspace program has to open them (hence it has a open file description
on them) and provide the appropriate source open file description.
By putting this distinction, we can early check if the user tried to
mount the second type of filesystems without a valid file description,
and fail with EBADF then.
Otherwise, we can proceed to either mount either type of filesystem,
provided that the fs_type is valid.
2022-05-28 14:52:48 +03:00
|
|
|
|
2022-05-28 15:42:03 +03:00
|
|
|
if (initializer_entry.requires_block_device && !description.file().is_block_device())
|
Kernel: Simplify mount syscall flow for regular calls
We do this by putting a distinction between two types of filesystems -
the first type is backed in RAM, and includes TmpFS, ProcFS, SysFS,
DevPtsFS and DevTmpFS. Because these filesystems are backed in RAM,
trying to mount them doesn't require source open file description.
The second type is filesystems that are backed by a file, therefore the
userspace program has to open them (hence it has a open file description
on them) and provide the appropriate source open file description.
By putting this distinction, we can early check if the user tried to
mount the second type of filesystems without a valid file description,
and fail with EBADF then.
Otherwise, we can proceed to either mount either type of filesystem,
provided that the fs_type is valid.
2022-05-28 14:52:48 +03:00
|
|
|
return ENOTBLK;
|
2022-05-28 15:42:03 +03:00
|
|
|
if (initializer_entry.requires_seekable_file && !description.file().is_seekable()) {
|
Kernel: Simplify mount syscall flow for regular calls
We do this by putting a distinction between two types of filesystems -
the first type is backed in RAM, and includes TmpFS, ProcFS, SysFS,
DevPtsFS and DevTmpFS. Because these filesystems are backed in RAM,
trying to mount them doesn't require source open file description.
The second type is filesystems that are backed by a file, therefore the
userspace program has to open them (hence it has a open file description
on them) and provide the appropriate source open file description.
By putting this distinction, we can early check if the user tried to
mount the second type of filesystems without a valid file description,
and fail with EBADF then.
Otherwise, we can proceed to either mount either type of filesystem,
provided that the fs_type is valid.
2022-05-28 14:52:48 +03:00
|
|
|
dbgln("mount: this is not a seekable file");
|
|
|
|
return ENODEV;
|
|
|
|
}
|
2022-08-20 00:03:24 +03:00
|
|
|
return TRY(VirtualFileSystem::the().find_already_existing_or_create_file_backed_file_system(description, initializer_entry.create_with_fd));
|
Kernel: Simplify mount syscall flow for regular calls
We do this by putting a distinction between two types of filesystems -
the first type is backed in RAM, and includes TmpFS, ProcFS, SysFS,
DevPtsFS and DevTmpFS. Because these filesystems are backed in RAM,
trying to mount them doesn't require source open file description.
The second type is filesystems that are backed by a file, therefore the
userspace program has to open them (hence it has a open file description
on them) and provide the appropriate source open file description.
By putting this distinction, we can early check if the user tried to
mount the second type of filesystems without a valid file description,
and fail with EBADF then.
Otherwise, we can proceed to either mount either type of filesystem,
provided that the fs_type is valid.
2022-05-28 14:52:48 +03:00
|
|
|
}
|
2022-05-28 15:42:03 +03:00
|
|
|
return ENODEV;
|
Kernel: Simplify mount syscall flow for regular calls
We do this by putting a distinction between two types of filesystems -
the first type is backed in RAM, and includes TmpFS, ProcFS, SysFS,
DevPtsFS and DevTmpFS. Because these filesystems are backed in RAM,
trying to mount them doesn't require source open file description.
The second type is filesystems that are backed by a file, therefore the
userspace program has to open them (hence it has a open file description
on them) and provide the appropriate source open file description.
By putting this distinction, we can early check if the user tried to
mount the second type of filesystems without a valid file description,
and fail with EBADF then.
Otherwise, we can proceed to either mount either type of filesystem,
provided that the fs_type is valid.
2022-05-28 14:52:48 +03:00
|
|
|
}
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
ErrorOr<FlatPtr> Process::sys$mount(Userspace<Syscall::SC_mount_params const*> user_params)
|
2020-07-30 23:38:15 +02:00
|
|
|
{
|
2022-08-17 21:03:04 +01:00
|
|
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
2021-12-29 01:11:45 -08:00
|
|
|
TRY(require_no_promises());
|
2022-08-20 18:21:01 -04:00
|
|
|
auto credentials = this->credentials();
|
|
|
|
if (!credentials->is_superuser())
|
2021-03-01 13:49:16 +01:00
|
|
|
return EPERM;
|
2020-07-30 23:38:15 +02:00
|
|
|
|
2021-09-05 17:51:37 +02:00
|
|
|
auto params = TRY(copy_typed_from_user(user_params));
|
2020-07-30 23:38:15 +02:00
|
|
|
|
|
|
|
auto source_fd = params.source_fd;
|
2021-09-05 18:20:57 +02:00
|
|
|
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();
|
2020-07-30 23:38:15 +02:00
|
|
|
|
2022-01-29 01:22:28 +01:00
|
|
|
auto description_or_error = open_file_description(source_fd);
|
2021-09-05 18:34:28 +02:00
|
|
|
if (!description_or_error.is_error())
|
2021-01-10 15:43:09 +01:00
|
|
|
dbgln("mount {}: source fd {} @ {}", fs_type, source_fd, target);
|
2020-07-30 23:38:15 +02:00
|
|
|
else
|
2021-01-10 15:43:09 +01:00
|
|
|
dbgln("mount {} @ {}", fs_type, target);
|
2020-07-30 23:38:15 +02:00
|
|
|
|
2022-08-20 18:21:01 -04:00
|
|
|
auto target_custody = TRY(VirtualFileSystem::the().resolve_path(credentials, target->view(), current_directory()));
|
2020-07-30 23:38:15 +02:00
|
|
|
|
|
|
|
if (params.flags & MS_REMOUNT) {
|
|
|
|
// We're not creating a new mount, we're updating an existing one!
|
2021-11-08 00:51:39 +01:00
|
|
|
TRY(VirtualFileSystem::the().remount(target_custody, params.flags & ~MS_REMOUNT));
|
|
|
|
return 0;
|
2020-07-30 23:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (params.flags & MS_BIND) {
|
|
|
|
// We're doing a bind mount.
|
2021-09-05 18:34:28 +02:00
|
|
|
if (description_or_error.is_error())
|
2021-11-08 00:51:39 +01:00
|
|
|
return description_or_error.release_error();
|
2021-09-05 18:34:28 +02:00
|
|
|
auto description = description_or_error.release_value();
|
2020-07-30 23:38:15 +02:00
|
|
|
if (!description->custody()) {
|
|
|
|
// We only support bind-mounting inodes, not arbitrary files.
|
2021-03-01 13:49:16 +01:00
|
|
|
return ENODEV;
|
2020-07-30 23:38:15 +02:00
|
|
|
}
|
2021-11-08 00:51:39 +01:00
|
|
|
TRY(VirtualFileSystem::the().bind_mount(*description->custody(), target_custody, params.flags));
|
|
|
|
return 0;
|
2020-07-30 23:38:15 +02:00
|
|
|
}
|
|
|
|
|
2022-08-19 20:53:40 +02:00
|
|
|
LockRefPtr<FileSystem> fs;
|
2020-07-30 23:38:15 +02:00
|
|
|
|
2022-05-28 15:42:03 +03:00
|
|
|
if (!description_or_error.is_error()) {
|
|
|
|
auto description = description_or_error.release_value();
|
2022-08-20 00:03:24 +03:00
|
|
|
fs = TRY(find_or_create_filesystem_instance(fs_type, description.ptr()));
|
2022-05-28 15:42:03 +03:00
|
|
|
auto source_pseudo_path = TRY(description->pseudo_path());
|
|
|
|
dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target);
|
|
|
|
} else {
|
2022-08-20 00:03:24 +03:00
|
|
|
fs = TRY(find_or_create_filesystem_instance(fs_type, {}));
|
Kernel: Simplify mount syscall flow for regular calls
We do this by putting a distinction between two types of filesystems -
the first type is backed in RAM, and includes TmpFS, ProcFS, SysFS,
DevPtsFS and DevTmpFS. Because these filesystems are backed in RAM,
trying to mount them doesn't require source open file description.
The second type is filesystems that are backed by a file, therefore the
userspace program has to open them (hence it has a open file description
on them) and provide the appropriate source open file description.
By putting this distinction, we can early check if the user tried to
mount the second type of filesystems without a valid file description,
and fail with EBADF then.
Otherwise, we can proceed to either mount either type of filesystem,
provided that the fs_type is valid.
2022-05-28 14:52:48 +03:00
|
|
|
}
|
2021-05-28 05:42:03 -07:00
|
|
|
|
2022-05-28 15:42:03 +03:00
|
|
|
TRY(fs->initialize());
|
|
|
|
TRY(VirtualFileSystem::the().mount(*fs, target_custody, params.flags));
|
2021-11-08 00:51:39 +01:00
|
|
|
return 0;
|
2020-07-30 23:38:15 +02:00
|
|
|
}
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
ErrorOr<FlatPtr> Process::sys$umount(Userspace<char const*> user_mountpoint, size_t mountpoint_length)
|
2020-07-30 23:38:15 +02:00
|
|
|
{
|
2022-08-17 21:03:04 +01:00
|
|
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
2022-08-20 18:21:01 -04:00
|
|
|
auto credentials = this->credentials();
|
|
|
|
if (!credentials->is_superuser())
|
2021-03-01 13:49:16 +01:00
|
|
|
return EPERM;
|
2020-07-30 23:38:15 +02:00
|
|
|
|
2021-12-29 01:11:45 -08:00
|
|
|
TRY(require_no_promises());
|
2020-07-30 23:38:15 +02:00
|
|
|
|
2021-09-05 18:18:23 +02:00
|
|
|
auto mountpoint = TRY(get_syscall_path_argument(user_mountpoint, mountpoint_length));
|
2022-08-20 18:21:01 -04:00
|
|
|
auto custody = TRY(VirtualFileSystem::the().resolve_path(credentials, mountpoint->view(), current_directory()));
|
2022-08-20 00:03:24 +03:00
|
|
|
TRY(VirtualFileSystem::the().unmount(*custody));
|
2021-11-08 00:51:39 +01:00
|
|
|
return 0;
|
2020-07-30 23:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|