ProcessExposed.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Debug.h>
  7. #include <Kernel/Devices/BlockDevice.h>
  8. #include <Kernel/FileSystem/ProcFS.h>
  9. #include <Kernel/FileSystem/VirtualFileSystem.h>
  10. #include <Kernel/KBufferBuilder.h>
  11. #include <Kernel/PerformanceEventBuffer.h>
  12. #include <Kernel/Process.h>
  13. #include <Kernel/ProcessExposed.h>
  14. namespace Kernel {
  15. static SpinLock<u8> s_index_lock;
  16. static InodeIndex s_next_inode_index = 0;
  17. static size_t s_allocate_inode_index()
  18. {
  19. ScopedSpinLock lock(s_index_lock);
  20. s_next_inode_index = s_next_inode_index.value() + 1;
  21. VERIFY(s_next_inode_index > 0);
  22. return s_next_inode_index.value();
  23. }
  24. InodeIndex ProcFSComponentRegistry::allocate_inode_index() const
  25. {
  26. return s_allocate_inode_index();
  27. }
  28. ProcFSExposedComponent::ProcFSExposedComponent(StringView name)
  29. : m_component_index(s_allocate_inode_index())
  30. {
  31. m_name = KString::try_create(name);
  32. }
  33. // Note: This constructor is intended to be used in /proc/pid/fd/* symlinks
  34. // so we preallocated inode index for them so we just need to set it here.
  35. ProcFSExposedComponent::ProcFSExposedComponent(StringView name, InodeIndex preallocated_index)
  36. : m_component_index(preallocated_index.value())
  37. {
  38. VERIFY(preallocated_index.value() != 0);
  39. VERIFY(preallocated_index <= s_next_inode_index);
  40. m_name = KString::try_create(name);
  41. }
  42. ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name)
  43. : ProcFSExposedComponent(name)
  44. {
  45. }
  46. ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name, const ProcFSExposedDirectory& parent_directory)
  47. : ProcFSExposedComponent(name)
  48. , m_parent_directory(parent_directory)
  49. {
  50. }
  51. ProcFSExposedLink::ProcFSExposedLink(StringView name)
  52. : ProcFSExposedComponent(name)
  53. {
  54. }
  55. ProcFSExposedLink::ProcFSExposedLink(StringView name, InodeIndex preallocated_index)
  56. : ProcFSExposedComponent(name, preallocated_index)
  57. {
  58. }
  59. struct ProcFSInodeData : public FileDescriptionData {
  60. OwnPtr<KBuffer> buffer;
  61. };
  62. KResultOr<size_t> ProcFSGlobalInformation::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
  63. {
  64. dbgln_if(PROCFS_DEBUG, "ProcFSGlobalInformation @ {}: read_bytes offset: {} count: {}", name(), offset, count);
  65. VERIFY(offset >= 0);
  66. VERIFY(buffer.user_or_kernel_ptr());
  67. if (!description)
  68. return KResult(EIO);
  69. MutexLocker locker(m_refresh_lock);
  70. if (!description->data()) {
  71. dbgln("ProcFSGlobalInformation: Do not have cached data!");
  72. return KResult(EIO);
  73. }
  74. auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
  75. auto& data_buffer = typed_cached_data.buffer;
  76. if (!data_buffer || (size_t)offset >= data_buffer->size())
  77. return 0;
  78. ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
  79. if (!buffer.write(data_buffer->data() + offset, nread))
  80. return KResult(EFAULT);
  81. return nread;
  82. }
  83. KResult ProcFSGlobalInformation::refresh_data(FileDescription& description) const
  84. {
  85. MutexLocker lock(m_refresh_lock);
  86. auto& cached_data = description.data();
  87. if (!cached_data) {
  88. cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
  89. if (!cached_data)
  90. return ENOMEM;
  91. }
  92. KBufferBuilder builder;
  93. if (!const_cast<ProcFSGlobalInformation&>(*this).output(builder))
  94. return ENOENT;
  95. auto& typed_cached_data = static_cast<ProcFSInodeData&>(*cached_data);
  96. typed_cached_data.buffer = builder.build();
  97. if (!typed_cached_data.buffer)
  98. return ENOMEM;
  99. return KSuccess;
  100. }
  101. KResultOr<size_t> ProcFSProcessInformation::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
  102. {
  103. dbgln_if(PROCFS_DEBUG, "ProcFSProcessInformation @ {}: read_bytes offset: {} count: {}", name(), offset, count);
  104. VERIFY(offset >= 0);
  105. VERIFY(buffer.user_or_kernel_ptr());
  106. if (!description)
  107. return KResult(EIO);
  108. if (!description->data()) {
  109. dbgln("ProcFSGlobalInformation: Do not have cached data!");
  110. return KResult(EIO);
  111. }
  112. MutexLocker locker(m_refresh_lock);
  113. auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
  114. auto& data_buffer = typed_cached_data.buffer;
  115. if (!data_buffer || (size_t)offset >= data_buffer->size())
  116. return 0;
  117. ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
  118. if (!buffer.write(data_buffer->data() + offset, nread))
  119. return KResult(EFAULT);
  120. return nread;
  121. }
  122. KResult ProcFSProcessInformation::refresh_data(FileDescription& description) const
  123. {
  124. // For process-specific inodes, hold the process's ptrace lock across refresh
  125. // and refuse to load data if the process is not dumpable.
  126. // Without this, files opened before a process went non-dumpable could still be used for dumping.
  127. auto parent_directory = const_cast<ProcFSProcessInformation&>(*this).m_parent_directory.strong_ref();
  128. if (parent_directory.is_null())
  129. return KResult(EINVAL);
  130. auto process = parent_directory->associated_process();
  131. if (!process)
  132. return KResult(ESRCH);
  133. process->ptrace_lock().lock();
  134. if (!process->is_dumpable()) {
  135. process->ptrace_lock().unlock();
  136. return EPERM;
  137. }
  138. ScopeGuard guard = [&] {
  139. process->ptrace_lock().unlock();
  140. };
  141. MutexLocker locker(m_refresh_lock);
  142. auto& cached_data = description.data();
  143. if (!cached_data) {
  144. cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
  145. if (!cached_data)
  146. return ENOMEM;
  147. }
  148. KBufferBuilder builder;
  149. if (!const_cast<ProcFSProcessInformation&>(*this).output(builder))
  150. return ENOENT;
  151. auto& typed_cached_data = static_cast<ProcFSInodeData&>(*cached_data);
  152. typed_cached_data.buffer = builder.build();
  153. if (!typed_cached_data.buffer)
  154. return ENOMEM;
  155. return KSuccess;
  156. }
  157. KResultOr<size_t> ProcFSExposedLink::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription*) const
  158. {
  159. VERIFY(offset == 0);
  160. MutexLocker locker(m_lock);
  161. KBufferBuilder builder;
  162. if (!const_cast<ProcFSExposedLink&>(*this).acquire_link(builder))
  163. return KResult(EFAULT);
  164. auto blob = builder.build();
  165. if (!blob)
  166. return KResult(EFAULT);
  167. ssize_t nread = min(static_cast<off_t>(blob->size() - offset), static_cast<off_t>(count));
  168. if (!buffer.write(blob->data() + offset, nread))
  169. return KResult(EFAULT);
  170. return nread;
  171. }
  172. NonnullRefPtr<Inode> ProcFSExposedLink::to_inode(const ProcFS& procfs_instance) const
  173. {
  174. return ProcFSLinkInode::create(procfs_instance, *this);
  175. }
  176. NonnullRefPtr<Inode> ProcFSExposedComponent::to_inode(const ProcFS& procfs_instance) const
  177. {
  178. return ProcFSInode::create(procfs_instance, *this);
  179. }
  180. NonnullRefPtr<Inode> ProcFSExposedDirectory::to_inode(const ProcFS& procfs_instance) const
  181. {
  182. return ProcFSDirectoryInode::create(procfs_instance, *this);
  183. }
  184. void ProcFSExposedDirectory::add_component(const ProcFSExposedComponent&)
  185. {
  186. TODO();
  187. }
  188. RefPtr<ProcFSExposedComponent> ProcFSExposedDirectory::lookup(StringView name)
  189. {
  190. for (auto& component : m_components) {
  191. if (component.name() == name) {
  192. return component;
  193. }
  194. }
  195. return {};
  196. }
  197. KResult ProcFSExposedDirectory::traverse_as_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
  198. {
  199. MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
  200. auto parent_directory = m_parent_directory.strong_ref();
  201. if (parent_directory.is_null())
  202. return KResult(EINVAL);
  203. callback({ ".", { fsid, component_index() }, 0 });
  204. callback({ "..", { fsid, parent_directory->component_index() }, 0 });
  205. for (auto& component : m_components) {
  206. InodeIdentifier identifier = { fsid, component.component_index() };
  207. callback({ component.name(), identifier, 0 });
  208. }
  209. return KSuccess;
  210. }
  211. }