ProcessExposed.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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. 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_directory = const_cast<ProcFSProcessInformation&>(*this).m_parent_directory.strong_ref();
  133. if (parent_directory.is_null())
  134. return KResult(EINVAL);
  135. auto process = parent_directory->associated_process();
  136. if (!process)
  137. return KResult(ESRCH);
  138. process->ptrace_lock().lock();
  139. if (!process->is_dumpable()) {
  140. process->ptrace_lock().unlock();
  141. return EPERM;
  142. }
  143. ScopeGuard guard = [&] {
  144. process->ptrace_lock().unlock();
  145. };
  146. ScopedSpinLock lock(m_refresh_lock);
  147. auto& cached_data = description.data();
  148. if (!cached_data)
  149. cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
  150. VERIFY(description.data());
  151. auto& buffer = static_cast<ProcFSInodeData&>(*cached_data).buffer;
  152. if (buffer) {
  153. // If we're reusing the buffer, reset the size to 0 first. This
  154. // ensures we don't accidentally leak previously written data.
  155. buffer->set_size(0);
  156. }
  157. KBufferBuilder builder(buffer, true);
  158. if (!const_cast<ProcFSProcessInformation&>(*this).output(builder))
  159. return ENOENT;
  160. // We don't use builder.build() here, which would steal our buffer
  161. // and turn it into an OwnPtr. Instead, just flush to the buffer so
  162. // that we can read all the data that was written.
  163. if (!builder.flush())
  164. return ENOMEM;
  165. if (!buffer)
  166. return ENOMEM;
  167. return KSuccess;
  168. }
  169. KResultOr<size_t> ProcFSExposedLink::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription*) const
  170. {
  171. VERIFY(offset == 0);
  172. Locker locker(m_lock);
  173. KBufferBuilder builder;
  174. if (!const_cast<ProcFSExposedLink&>(*this).acquire_link(builder))
  175. return KResult(EFAULT);
  176. auto blob = builder.build();
  177. if (!blob)
  178. return KResult(EFAULT);
  179. ssize_t nread = min(static_cast<off_t>(blob->size() - offset), static_cast<off_t>(count));
  180. if (!buffer.write(blob->data() + offset, nread))
  181. return KResult(EFAULT);
  182. return nread;
  183. }
  184. NonnullRefPtr<Inode> ProcFSExposedLink::to_inode(const ProcFS& procfs_instance) const
  185. {
  186. return ProcFSLinkInode::create(procfs_instance, *this);
  187. }
  188. NonnullRefPtr<Inode> ProcFSExposedComponent::to_inode(const ProcFS& procfs_instance) const
  189. {
  190. return ProcFSInode::create(procfs_instance, *this);
  191. }
  192. NonnullRefPtr<Inode> ProcFSExposedDirectory::to_inode(const ProcFS& procfs_instance) const
  193. {
  194. return ProcFSDirectoryInode::create(procfs_instance, *this);
  195. }
  196. void ProcFSExposedDirectory::add_component(const ProcFSExposedComponent&)
  197. {
  198. TODO();
  199. }
  200. RefPtr<ProcFSExposedComponent> ProcFSExposedDirectory::lookup(StringView name)
  201. {
  202. for (auto& component : m_components) {
  203. if (component.name() == name) {
  204. return component;
  205. }
  206. }
  207. return {};
  208. }
  209. KResult ProcFSExposedDirectory::traverse_as_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
  210. {
  211. Locker locker(ProcFSComponentRegistry::the().get_lock());
  212. auto parent_directory = m_parent_directory.strong_ref();
  213. if (parent_directory.is_null())
  214. return KResult(EINVAL);
  215. callback({ ".", { fsid, component_index() }, 0 });
  216. callback({ "..", { fsid, parent_directory->component_index() }, 0 });
  217. for (auto& component : m_components) {
  218. InodeIdentifier identifier = { fsid, component.component_index() };
  219. callback({ component.name(), identifier, 0 });
  220. }
  221. return KSuccess;
  222. }
  223. }