2022-12-15 11:42:40 +02:00
|
|
|
/*
|
2024-07-14 14:07:23 +03:00
|
|
|
* Copyright (c) 2022-2024, Liav A. <liavalb@hotmail.co.il>
|
2022-12-15 11:42:40 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
2024-07-14 14:07:23 +03:00
|
|
|
#include <AK/StdLibExtras.h>
|
2022-12-15 11:42:40 +02:00
|
|
|
#include <AK/StringView.h>
|
|
|
|
#include <Kernel/API/FileSystem/MountSpecificFlags.h>
|
|
|
|
#include <Kernel/API/Ioctl.h>
|
|
|
|
#include <Kernel/API/POSIX/errno.h>
|
|
|
|
#include <Kernel/API/POSIX/unistd.h>
|
2023-07-17 19:22:01 +03:00
|
|
|
#include <Kernel/API/Syscall.h>
|
2022-12-15 11:42:40 +02:00
|
|
|
#include <Kernel/FileSystem/Inode.h>
|
|
|
|
#include <Kernel/FileSystem/MountFile.h>
|
|
|
|
#include <Kernel/FileSystem/OpenFileDescription.h>
|
|
|
|
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
|
|
|
#include <Kernel/Library/StdLib.h>
|
|
|
|
#include <Kernel/Memory/PrivateInodeVMObject.h>
|
|
|
|
#include <Kernel/Memory/SharedInodeVMObject.h>
|
2023-07-17 19:22:01 +03:00
|
|
|
#include <Kernel/Tasks/Process.h>
|
2022-12-15 11:42:40 +02:00
|
|
|
|
|
|
|
namespace Kernel {
|
|
|
|
|
|
|
|
ErrorOr<NonnullLockRefPtr<MountFile>> MountFile::create(FileSystemInitializer const& file_system_initializer, int flags)
|
|
|
|
{
|
|
|
|
// NOTE: We should not open a MountFile if someone wants to either remount or bindmount.
|
|
|
|
// There's a check for this in the fsopen syscall entry handler, but here we just assert
|
|
|
|
// to ensure this never happens.
|
|
|
|
VERIFY(!(flags & MS_BIND));
|
|
|
|
VERIFY(!(flags & MS_REMOUNT));
|
2024-07-14 14:07:23 +03:00
|
|
|
return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) MountFile(file_system_initializer, flags)));
|
2022-12-15 11:42:40 +02:00
|
|
|
}
|
|
|
|
|
2024-07-14 14:07:23 +03:00
|
|
|
MountFile::MountFile(FileSystemInitializer const& file_system_initializer, int flags)
|
2022-12-15 11:42:40 +02:00
|
|
|
: m_flags(flags)
|
|
|
|
, m_file_system_initializer(file_system_initializer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
MountFile::~MountFile() = default;
|
|
|
|
|
2024-07-14 14:07:23 +03:00
|
|
|
static ErrorOr<void> verify_mount_specific_option_data(MountSpecificFlag const& data)
|
|
|
|
{
|
|
|
|
// NOTE: We put this limit in place because we assume that don't need to handle huge
|
|
|
|
// amounts of bytes when trying to handle a mount fs-specific flag. A zero-sized value
|
|
|
|
// is also not valid either.
|
|
|
|
// Anything larger than this constant (which could be changed if needed) is deemed to
|
|
|
|
// potentially cause OOM condition, and cannot represent any reasonable and "honest" data
|
|
|
|
// from userspace.
|
|
|
|
constexpr auto value_max_size = max(sizeof(unsigned),
|
|
|
|
max(sizeof(signed),
|
|
|
|
sizeof(u64)));
|
|
|
|
|
|
|
|
if (data.value_length == 0)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if (data.value_length > value_max_size)
|
|
|
|
return E2BIG;
|
|
|
|
|
|
|
|
if (data.value_addr == nullptr)
|
|
|
|
return EFAULT;
|
|
|
|
|
|
|
|
switch (data.value_type) {
|
|
|
|
case MountSpecificFlag::ValueType::SignedInteger:
|
|
|
|
case MountSpecificFlag::ValueType::Boolean:
|
|
|
|
case MountSpecificFlag::ValueType::UnsignedInteger:
|
|
|
|
return {};
|
|
|
|
|
|
|
|
default:
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-15 11:42:40 +02:00
|
|
|
ErrorOr<void> MountFile::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
|
|
|
|
{
|
2024-07-14 14:07:23 +03:00
|
|
|
return m_filesystem_specific_options.with_exclusive([&](auto& filesystem_specific_options) -> ErrorOr<void> {
|
|
|
|
auto user_mount_specific_data = static_ptr_cast<MountSpecificFlag const*>(arg);
|
|
|
|
auto mount_specific_data = TRY(copy_typed_from_user(user_mount_specific_data));
|
|
|
|
|
|
|
|
Syscall::StringArgument user_key_string { reinterpret_cast<char const*>(mount_specific_data.key_string_addr), static_cast<size_t>(mount_specific_data.key_string_length) };
|
|
|
|
auto key_string = TRY(Process::get_syscall_name_string_fixed_buffer<MOUNT_SPECIFIC_FLAG_KEY_STRING_MAX_LENGTH>(user_key_string));
|
|
|
|
|
2022-12-15 11:42:40 +02:00
|
|
|
switch (request) {
|
2024-07-14 14:07:23 +03:00
|
|
|
case MOUNT_IOCTL_DELETE_MOUNT_SPECIFIC_FLAG: {
|
|
|
|
if (!filesystem_specific_options.remove(key_string.representable_view()))
|
|
|
|
dbgln("MountFile: WARNING: mount option by key {} was not found, deletion request ignored", key_string.representable_view());
|
|
|
|
return {};
|
|
|
|
}
|
2022-12-15 11:42:40 +02:00
|
|
|
case MOUNT_IOCTL_SET_MOUNT_SPECIFIC_FLAG: {
|
2024-07-14 14:07:23 +03:00
|
|
|
TRY(verify_mount_specific_option_data(mount_specific_data));
|
|
|
|
if (filesystem_specific_options.get(key_string.representable_view()).has_value())
|
|
|
|
return Error::from_errno(EEXIST);
|
2023-07-17 19:22:01 +03:00
|
|
|
|
2024-07-14 14:07:23 +03:00
|
|
|
auto add_key_with_value = [&filesystem_specific_options](StringView name, NonnullOwnPtr<FileSystemSpecificOption> option) -> ErrorOr<void> {
|
|
|
|
auto kstring_name = TRY(KString::try_create(name));
|
|
|
|
auto result = TRY(filesystem_specific_options.try_set(move(kstring_name), move(option)));
|
|
|
|
// NOTE: We checked earlier that there's no matching entry, so we must have a result
|
|
|
|
// of newly inserted entry.
|
|
|
|
VERIFY(result == HashSetResult::InsertedNewEntry);
|
|
|
|
return {};
|
|
|
|
};
|
2022-12-15 11:42:40 +02:00
|
|
|
|
|
|
|
// NOTE: We enforce that the passed argument will be either i64 or u64, so it will always be
|
|
|
|
// exactly 8 bytes. We do that to simplify handling of integers as well as to ensure ABI correctness
|
|
|
|
// in all possible cases.
|
|
|
|
switch (mount_specific_data.value_type) {
|
|
|
|
// NOTE: This is actually considered as simply boolean flag.
|
|
|
|
case MountSpecificFlag::ValueType::Boolean: {
|
2024-07-14 14:07:23 +03:00
|
|
|
VERIFY(m_file_system_initializer.validate_mount_boolean_flag);
|
2022-12-15 11:42:40 +02:00
|
|
|
Userspace<u64*> user_value_addr(reinterpret_cast<FlatPtr>(mount_specific_data.value_addr));
|
|
|
|
auto value_integer = TRY(copy_typed_from_user(user_value_addr));
|
|
|
|
if (value_integer != 0 && value_integer != 1)
|
|
|
|
return EDOM;
|
|
|
|
bool value = (value_integer == 1) ? true : false;
|
2024-07-14 14:07:23 +03:00
|
|
|
TRY(m_file_system_initializer.validate_mount_boolean_flag(key_string.representable_view(), value));
|
|
|
|
|
|
|
|
auto file_system_specific_option = TRY(FileSystemSpecificOption::create_as_boolean(value));
|
|
|
|
TRY(add_key_with_value(key_string.representable_view(), move(file_system_specific_option)));
|
2022-12-15 11:42:40 +02:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
case MountSpecificFlag::ValueType::UnsignedInteger: {
|
2024-07-14 14:07:23 +03:00
|
|
|
VERIFY(m_file_system_initializer.validate_mount_unsigned_integer_flag);
|
2022-12-15 11:42:40 +02:00
|
|
|
Userspace<u64*> user_value_addr(reinterpret_cast<FlatPtr>(mount_specific_data.value_addr));
|
|
|
|
auto value_integer = TRY(copy_typed_from_user(user_value_addr));
|
2024-07-14 14:07:23 +03:00
|
|
|
TRY(m_file_system_initializer.validate_mount_unsigned_integer_flag(key_string.representable_view(), value_integer));
|
|
|
|
|
|
|
|
auto file_system_specific_option = TRY(FileSystemSpecificOption::create_as_unsigned(value_integer));
|
|
|
|
TRY(add_key_with_value(key_string.representable_view(), move(file_system_specific_option)));
|
2022-12-15 11:42:40 +02:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
case MountSpecificFlag::ValueType::SignedInteger: {
|
2024-07-14 14:07:23 +03:00
|
|
|
VERIFY(m_file_system_initializer.validate_mount_signed_integer_flag);
|
2022-12-15 11:42:40 +02:00
|
|
|
Userspace<i64*> user_value_addr(reinterpret_cast<FlatPtr>(mount_specific_data.value_addr));
|
|
|
|
auto value_integer = TRY(copy_typed_from_user(user_value_addr));
|
2024-07-14 14:07:23 +03:00
|
|
|
TRY(m_file_system_initializer.validate_mount_signed_integer_flag(key_string.representable_view(), value_integer));
|
|
|
|
|
|
|
|
auto file_system_specific_option = TRY(FileSystemSpecificOption::create_as_signed(value_integer));
|
|
|
|
TRY(add_key_with_value(key_string.representable_view(), move(file_system_specific_option)));
|
2022-12-15 11:42:40 +02:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<NonnullOwnPtr<KString>> MountFile::pseudo_path(OpenFileDescription const&) const
|
|
|
|
{
|
|
|
|
return KString::try_create(":mount-file:"sv);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|