MountFile.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * Copyright (c) 2022-2023, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/StringView.h>
  7. #include <Kernel/API/FileSystem/MountSpecificFlags.h>
  8. #include <Kernel/API/Ioctl.h>
  9. #include <Kernel/API/POSIX/errno.h>
  10. #include <Kernel/API/POSIX/unistd.h>
  11. #include <Kernel/API/Syscall.h>
  12. #include <Kernel/FileSystem/Inode.h>
  13. #include <Kernel/FileSystem/MountFile.h>
  14. #include <Kernel/FileSystem/OpenFileDescription.h>
  15. #include <Kernel/FileSystem/VirtualFileSystem.h>
  16. #include <Kernel/Library/StdLib.h>
  17. #include <Kernel/Memory/PrivateInodeVMObject.h>
  18. #include <Kernel/Memory/SharedInodeVMObject.h>
  19. #include <Kernel/Tasks/Process.h>
  20. namespace Kernel {
  21. ErrorOr<NonnullLockRefPtr<MountFile>> MountFile::create(FileSystemInitializer const& file_system_initializer, int flags)
  22. {
  23. // NOTE: We should not open a MountFile if someone wants to either remount or bindmount.
  24. // There's a check for this in the fsopen syscall entry handler, but here we just assert
  25. // to ensure this never happens.
  26. VERIFY(!(flags & MS_BIND));
  27. VERIFY(!(flags & MS_REMOUNT));
  28. auto mount_specific_data_buffer = TRY(KBuffer::try_create_with_size("Mount Specific Data"sv, PAGE_SIZE, Memory::Region::Access::ReadWrite, AllocationStrategy::AllocateNow));
  29. return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) MountFile(file_system_initializer, flags, move(mount_specific_data_buffer))));
  30. }
  31. MountFile::MountFile(FileSystemInitializer const& file_system_initializer, int flags, NonnullOwnPtr<KBuffer> mount_specific_data)
  32. : m_flags(flags)
  33. , m_file_system_initializer(file_system_initializer)
  34. {
  35. m_mount_specific_data.with_exclusive([&](auto& our_mount_specific_data) {
  36. our_mount_specific_data = move(mount_specific_data);
  37. memset(our_mount_specific_data->data(), 0, our_mount_specific_data->size());
  38. });
  39. }
  40. MountFile::~MountFile() = default;
  41. ErrorOr<void> MountFile::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
  42. {
  43. return m_mount_specific_data.with_exclusive([&](auto& our_mount_specific_data) -> ErrorOr<void> {
  44. switch (request) {
  45. case MOUNT_IOCTL_SET_MOUNT_SPECIFIC_FLAG: {
  46. auto user_mount_specific_data = static_ptr_cast<MountSpecificFlag const*>(arg);
  47. auto mount_specific_data = TRY(copy_typed_from_user(user_mount_specific_data));
  48. if ((mount_specific_data.value_type == MountSpecificFlag::ValueType::SignedInteger || mount_specific_data.value_type == MountSpecificFlag::ValueType::UnsignedInteger) && mount_specific_data.value_length != 8)
  49. return EDOM;
  50. 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) };
  51. auto key_string = TRY(Process::get_syscall_name_string_fixed_buffer<MOUNT_SPECIFIC_FLAG_KEY_STRING_MAX_LENGTH>(user_key_string));
  52. if (mount_specific_data.value_type != MountSpecificFlag::ValueType::Boolean && mount_specific_data.value_length == 0)
  53. return EINVAL;
  54. if (mount_specific_data.value_type != MountSpecificFlag::ValueType::Boolean && mount_specific_data.value_addr == nullptr)
  55. return EFAULT;
  56. // NOTE: We put these limits in place because we assume that don't need to handle huge
  57. // amounts of bytes when trying to handle a mount fs-specific flag.
  58. // Anything larger than these constants (which could be changed if needed) is deemed to
  59. // potentially cause OOM condition, and cannot represent any reasonable and "honest" data
  60. // from userspace.
  61. if (mount_specific_data.value_type != MountSpecificFlag::ValueType::ASCIIString && mount_specific_data.value_length > MOUNT_SPECIFIC_FLAG_NON_ASCII_STRING_TYPE_MAX_LENGTH)
  62. return E2BIG;
  63. if (mount_specific_data.value_type == MountSpecificFlag::ValueType::ASCIIString && mount_specific_data.value_length > MOUNT_SPECIFIC_FLAG_ASCII_STRING_TYPE_MAX_LENGTH)
  64. return E2BIG;
  65. // NOTE: We enforce that the passed argument will be either i64 or u64, so it will always be
  66. // exactly 8 bytes. We do that to simplify handling of integers as well as to ensure ABI correctness
  67. // in all possible cases.
  68. switch (mount_specific_data.value_type) {
  69. // NOTE: This is actually considered as simply boolean flag.
  70. case MountSpecificFlag::ValueType::Boolean: {
  71. VERIFY(m_file_system_initializer.handle_mount_boolean_flag);
  72. Userspace<u64*> user_value_addr(reinterpret_cast<FlatPtr>(mount_specific_data.value_addr));
  73. auto value_integer = TRY(copy_typed_from_user(user_value_addr));
  74. if (value_integer != 0 && value_integer != 1)
  75. return EDOM;
  76. bool value = (value_integer == 1) ? true : false;
  77. TRY(m_file_system_initializer.handle_mount_boolean_flag(our_mount_specific_data->bytes(), key_string.representable_view(), value));
  78. return {};
  79. }
  80. case MountSpecificFlag::ValueType::UnsignedInteger: {
  81. VERIFY(m_file_system_initializer.handle_mount_unsigned_integer_flag);
  82. Userspace<u64*> user_value_addr(reinterpret_cast<FlatPtr>(mount_specific_data.value_addr));
  83. auto value_integer = TRY(copy_typed_from_user(user_value_addr));
  84. TRY(m_file_system_initializer.handle_mount_unsigned_integer_flag(our_mount_specific_data->bytes(), key_string.representable_view(), value_integer));
  85. return {};
  86. }
  87. case MountSpecificFlag::ValueType::SignedInteger: {
  88. VERIFY(m_file_system_initializer.handle_mount_signed_integer_flag);
  89. Userspace<i64*> user_value_addr(reinterpret_cast<FlatPtr>(mount_specific_data.value_addr));
  90. auto value_integer = TRY(copy_typed_from_user(user_value_addr));
  91. TRY(m_file_system_initializer.handle_mount_signed_integer_flag(our_mount_specific_data->bytes(), key_string.representable_view(), value_integer));
  92. return {};
  93. }
  94. case MountSpecificFlag::ValueType::ASCIIString: {
  95. VERIFY(m_file_system_initializer.handle_mount_ascii_string_flag);
  96. auto value_string = TRY(try_copy_kstring_from_user(reinterpret_cast<FlatPtr>(mount_specific_data.value_addr), static_cast<size_t>(mount_specific_data.value_length)));
  97. TRY(m_file_system_initializer.handle_mount_ascii_string_flag(our_mount_specific_data->bytes(), key_string.representable_view(), value_string->view()));
  98. return {};
  99. }
  100. default:
  101. return EINVAL;
  102. }
  103. }
  104. default:
  105. return EINVAL;
  106. }
  107. });
  108. }
  109. ErrorOr<NonnullOwnPtr<KString>> MountFile::pseudo_path(OpenFileDescription const&) const
  110. {
  111. return KString::try_create(":mount-file:"sv);
  112. }
  113. }