ProcessExposed.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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 ProcFSComponentsRegistrar::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_folder)
  47. : ProcFSExposedComponent(name)
  48. , m_parent_folder(parent_folder)
  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. RefPtr<KBufferImpl> 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. if (!description->data()) {
  70. dbgln("ProcFSGlobalInformation: Do not have cached data!");
  71. return KResult(EIO);
  72. }
  73. // Be sure to keep a reference to data_buffer while we use it!
  74. RefPtr<KBufferImpl> data_buffer = static_cast<ProcFSInodeData&>(*description->data()).buffer;
  75. if (!data_buffer || (size_t)offset >= data_buffer->size())
  76. return 0;
  77. ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
  78. if (!buffer.write(data_buffer->data() + offset, nread))
  79. return KResult(EFAULT);
  80. return nread;
  81. }
  82. KResult ProcFSGlobalInformation::refresh_data(FileDescription& description) const
  83. {
  84. ScopedSpinLock lock(m_refresh_lock);
  85. auto& cached_data = description.data();
  86. if (!cached_data)
  87. cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
  88. VERIFY(description.data());
  89. auto& buffer = static_cast<ProcFSInodeData&>(*cached_data).buffer;
  90. if (buffer) {
  91. // If we're reusing the buffer, reset the size to 0 first. This
  92. // ensures we don't accidentally leak previously written data.
  93. buffer->set_size(0);
  94. }
  95. KBufferBuilder builder(buffer, true);
  96. if (!const_cast<ProcFSGlobalInformation&>(*this).output(builder))
  97. return ENOENT;
  98. // We don't use builder.build() here, which would steal our buffer
  99. // and turn it into an OwnPtr. Instead, just flush to the buffer so
  100. // that we can read all the data that was written.
  101. if (!builder.flush())
  102. return ENOMEM;
  103. if (!buffer)
  104. return ENOMEM;
  105. return KSuccess;
  106. }
  107. KResultOr<size_t> ProcFSProcessInformation::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
  108. {
  109. dbgln_if(PROCFS_DEBUG, "ProcFSProcessInformation @ {}: read_bytes offset: {} count: {}", name(), offset, count);
  110. VERIFY(offset >= 0);
  111. VERIFY(buffer.user_or_kernel_ptr());
  112. if (!description)
  113. return KResult(EIO);
  114. if (!description->data()) {
  115. dbgln("ProcFSGlobalInformation: Do not have cached data!");
  116. return KResult(EIO);
  117. }
  118. // Be sure to keep a reference to data_buffer while we use it!
  119. RefPtr<KBufferImpl> data_buffer = static_cast<ProcFSInodeData&>(*description->data()).buffer;
  120. if (!data_buffer || (size_t)offset >= data_buffer->size())
  121. return 0;
  122. ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
  123. if (!buffer.write(data_buffer->data() + offset, nread))
  124. return KResult(EFAULT);
  125. return nread;
  126. }
  127. KResult ProcFSProcessInformation::refresh_data(FileDescription& description) const
  128. {
  129. // For process-specific inodes, hold the process's ptrace lock across refresh
  130. // and refuse to load data if the process is not dumpable.
  131. // Without this, files opened before a process went non-dumpable could still be used for dumping.
  132. auto parent_folder = const_cast<ProcFSProcessInformation&>(*this).m_parent_folder.strong_ref();
  133. if (parent_folder.is_null())
  134. return KResult(EINVAL);
  135. auto process = parent_folder->m_associated_process;
  136. process->ptrace_lock().lock();
  137. if (!process->is_dumpable()) {
  138. process->ptrace_lock().unlock();
  139. return EPERM;
  140. }
  141. ScopeGuard guard = [&] {
  142. process->ptrace_lock().unlock();
  143. };
  144. ScopedSpinLock lock(m_refresh_lock);
  145. auto& cached_data = description.data();
  146. if (!cached_data)
  147. cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
  148. VERIFY(description.data());
  149. auto& buffer = static_cast<ProcFSInodeData&>(*cached_data).buffer;
  150. if (buffer) {
  151. // If we're reusing the buffer, reset the size to 0 first. This
  152. // ensures we don't accidentally leak previously written data.
  153. buffer->set_size(0);
  154. }
  155. KBufferBuilder builder(buffer, true);
  156. if (!const_cast<ProcFSProcessInformation&>(*this).output(builder))
  157. return ENOENT;
  158. // We don't use builder.build() here, which would steal our buffer
  159. // and turn it into an OwnPtr. Instead, just flush to the buffer so
  160. // that we can read all the data that was written.
  161. if (!builder.flush())
  162. return ENOMEM;
  163. if (!buffer)
  164. return ENOMEM;
  165. return KSuccess;
  166. }
  167. KResultOr<size_t> ProcFSExposedLink::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription*) const
  168. {
  169. VERIFY(offset == 0);
  170. Locker locker(m_lock);
  171. KBufferBuilder builder;
  172. if (!const_cast<ProcFSExposedLink&>(*this).acquire_link(builder))
  173. return KResult(EFAULT);
  174. auto blob = builder.build();
  175. if (!blob)
  176. return KResult(EFAULT);
  177. ssize_t nread = min(static_cast<off_t>(blob->size() - offset), static_cast<off_t>(count));
  178. if (!buffer.write(blob->data() + offset, nread))
  179. return KResult(EFAULT);
  180. return nread;
  181. }
  182. NonnullRefPtr<Inode> ProcFSExposedLink::to_inode(const ProcFS& procfs_instance) const
  183. {
  184. return ProcFSLinkInode::create(procfs_instance, *this);
  185. }
  186. NonnullRefPtr<Inode> ProcFSExposedComponent::to_inode(const ProcFS& procfs_instance) const
  187. {
  188. return ProcFSInode::create(procfs_instance, *this);
  189. }
  190. NonnullRefPtr<Inode> ProcFSExposedDirectory::to_inode(const ProcFS& procfs_instance) const
  191. {
  192. return ProcFSDirectoryInode::create(procfs_instance, *this);
  193. }
  194. void ProcFSExposedDirectory::add_component(const ProcFSExposedComponent&)
  195. {
  196. TODO();
  197. }
  198. RefPtr<ProcFSExposedComponent> ProcFSExposedDirectory::lookup(StringView name)
  199. {
  200. for (auto& component : m_components) {
  201. if (component.name() == name) {
  202. return component;
  203. }
  204. }
  205. return {};
  206. }
  207. KResult ProcFSExposedDirectory::traverse_as_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
  208. {
  209. Locker locker(ProcFSComponentsRegistrar::the().get_lock());
  210. auto parent_folder = m_parent_folder.strong_ref();
  211. if (parent_folder.is_null())
  212. return KResult(EINVAL);
  213. callback({ ".", { fsid, component_index() }, 0 });
  214. callback({ "..", { fsid, parent_folder->component_index() }, 0 });
  215. for (auto& component : m_components) {
  216. InodeIdentifier identifier = { fsid, component.component_index() };
  217. callback({ component.name(), identifier, 0 });
  218. }
  219. return KSuccess;
  220. }
  221. }