ProcessSpecificExposed.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/JsonArraySerializer.h>
  7. #include <AK/JsonObjectSerializer.h>
  8. #include <AK/JsonValue.h>
  9. #include <Kernel/Arch/InterruptDisabler.h>
  10. #include <Kernel/FileSystem/Custody.h>
  11. #include <Kernel/FileSystem/ProcFS.h>
  12. #include <Kernel/KBufferBuilder.h>
  13. #include <Kernel/Memory/AnonymousVMObject.h>
  14. #include <Kernel/Memory/MemoryManager.h>
  15. #include <Kernel/Process.h>
  16. #include <Kernel/ProcessExposed.h>
  17. #include <Kernel/TTY/TTY.h>
  18. namespace Kernel {
  19. ErrorOr<void> Process::procfs_get_thread_stack(ThreadID thread_id, KBufferBuilder& builder) const
  20. {
  21. auto array = TRY(JsonArraySerializer<>::try_create(builder));
  22. auto thread = Thread::from_tid(thread_id);
  23. if (!thread)
  24. return ESRCH;
  25. bool show_kernel_addresses = Process::current().is_superuser();
  26. bool kernel_address_added = false;
  27. for (auto address : TRY(Processor::capture_stack_trace(*thread, 1024))) {
  28. if (!show_kernel_addresses && !Memory::is_user_address(VirtualAddress { address })) {
  29. if (kernel_address_added)
  30. continue;
  31. address = 0xdeadc0de;
  32. kernel_address_added = true;
  33. }
  34. TRY(array.add(address));
  35. }
  36. TRY(array.finish());
  37. return {};
  38. }
  39. ErrorOr<void> Process::traverse_stacks_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
  40. {
  41. TRY(callback({ ".", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, SegmentedProcFSIndex::MainProcessProperty::Reserved) }, 0 }));
  42. TRY(callback({ "..", { fsid, m_procfs_traits->component_index() }, 0 }));
  43. return thread_list().with([&](auto& list) -> ErrorOr<void> {
  44. for (auto const& thread : list) {
  45. int tid = thread.tid().value();
  46. InodeIdentifier identifier = { fsid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid(), thread.tid()) };
  47. auto name = TRY(KString::number(tid));
  48. TRY(callback({ name->view(), identifier, 0 }));
  49. }
  50. return {};
  51. });
  52. }
  53. ErrorOr<NonnullRefPtr<Inode>> Process::lookup_stacks_directory(ProcFS const& procfs, StringView name) const
  54. {
  55. auto maybe_needle = name.to_uint();
  56. if (!maybe_needle.has_value())
  57. return ENOENT;
  58. auto needle = maybe_needle.release_value();
  59. ErrorOr<NonnullRefPtr<ProcFSProcessPropertyInode>> thread_stack_inode { ENOENT };
  60. for_each_thread([&](Thread const& thread) {
  61. int tid = thread.tid().value();
  62. VERIFY(!(tid < 0));
  63. if (needle == (unsigned)tid) {
  64. thread_stack_inode = ProcFSProcessPropertyInode::try_create_for_thread_stack(procfs, thread.tid(), pid());
  65. return IterationDecision::Break;
  66. }
  67. return IterationDecision::Continue;
  68. });
  69. if (thread_stack_inode.is_error())
  70. return thread_stack_inode.release_error();
  71. return thread_stack_inode.release_value();
  72. }
  73. ErrorOr<void> Process::traverse_children_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
  74. {
  75. TRY(callback({ ".", { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Children) }, 0 }));
  76. TRY(callback({ "..", { fsid, m_procfs_traits->component_index() }, 0 }));
  77. return Process::all_instances().with([&](auto& processes) -> ErrorOr<void> {
  78. for (auto& process : processes) {
  79. if (process.ppid() == pid()) {
  80. StringBuilder builder;
  81. builder.appendff("{}", process.pid());
  82. TRY(callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_children(pid(), process.pid()) }, DT_LNK }));
  83. }
  84. }
  85. return {};
  86. });
  87. }
  88. ErrorOr<NonnullRefPtr<Inode>> Process::lookup_children_directory(ProcFS const& procfs, StringView name) const
  89. {
  90. auto maybe_pid = name.to_uint();
  91. if (!maybe_pid.has_value())
  92. return ENOENT;
  93. auto child_process = Process::from_pid(*maybe_pid);
  94. if (!child_process || child_process->ppid() != pid())
  95. return ENOENT;
  96. return TRY(ProcFSProcessPropertyInode::try_create_for_child_process_link(procfs, *maybe_pid, pid()));
  97. }
  98. ErrorOr<size_t> Process::procfs_get_child_proccess_link(ProcessID child_pid, KBufferBuilder& builder) const
  99. {
  100. TRY(builder.appendff("/proc/{}", child_pid.value()));
  101. return builder.length();
  102. }
  103. ErrorOr<size_t> Process::procfs_get_file_description_link(unsigned fd, KBufferBuilder& builder) const
  104. {
  105. auto file_description = TRY(open_file_description(fd));
  106. // Note: These links are not guaranteed to point to actual VFS paths, just like in other kernels.
  107. auto data = TRY(file_description->pseudo_path());
  108. TRY(builder.append(data->view()));
  109. return data->length();
  110. }
  111. ErrorOr<void> Process::traverse_file_descriptions_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
  112. {
  113. TRY(callback({ ".", { fsid, m_procfs_traits->component_index() }, 0 }));
  114. TRY(callback({ "..", { fsid, m_procfs_traits->component_index() }, 0 }));
  115. size_t count = 0;
  116. fds().with_shared([&](auto& fds) {
  117. fds.enumerate([&](auto& file_description_metadata) {
  118. if (!file_description_metadata.is_valid()) {
  119. count++;
  120. return;
  121. }
  122. StringBuilder builder;
  123. builder.appendff("{}", count);
  124. // FIXME: Propagate errors from callback.
  125. (void)callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid(), count) }, DT_LNK });
  126. count++;
  127. });
  128. });
  129. return {};
  130. }
  131. ErrorOr<NonnullRefPtr<Inode>> Process::lookup_file_descriptions_directory(ProcFS const& procfs, StringView name) const
  132. {
  133. auto maybe_index = name.to_uint();
  134. if (!maybe_index.has_value())
  135. return ENOENT;
  136. if (!m_fds.with_shared([&](auto& fds) { return fds.get_if_valid(*maybe_index); }))
  137. return ENOENT;
  138. return TRY(ProcFSProcessPropertyInode::try_create_for_file_description_link(procfs, *maybe_index, pid()));
  139. }
  140. ErrorOr<void> Process::procfs_get_pledge_stats(KBufferBuilder& builder) const
  141. {
  142. auto obj = TRY(JsonObjectSerializer<>::try_create(builder));
  143. #define __ENUMERATE_PLEDGE_PROMISE(x) \
  144. if (has_promised(Pledge::x)) { \
  145. if (!promises_builder.is_empty()) \
  146. TRY(promises_builder.try_append(' ')); \
  147. TRY(promises_builder.try_append(#x)); \
  148. }
  149. if (has_promises()) {
  150. StringBuilder promises_builder;
  151. ENUMERATE_PLEDGE_PROMISES
  152. TRY(obj.add("promises", promises_builder.string_view()));
  153. }
  154. #undef __ENUMERATE_PLEDGE_PROMISE
  155. TRY(obj.finish());
  156. return {};
  157. }
  158. ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
  159. {
  160. auto array = TRY(JsonArraySerializer<>::try_create(builder));
  161. TRY(m_unveil_data.with([&](auto& unveil_data) -> ErrorOr<void> {
  162. TRY(unveil_data.paths.for_each_node_in_tree_order([&](auto const& unveiled_path) -> ErrorOr<IterationDecision> {
  163. if (!unveiled_path.was_explicitly_unveiled())
  164. return IterationDecision::Continue;
  165. auto obj = TRY(array.add_object());
  166. TRY(obj.add("path", unveiled_path.path()));
  167. StringBuilder permissions_builder;
  168. if (unveiled_path.permissions() & UnveilAccess::Read)
  169. permissions_builder.append('r');
  170. if (unveiled_path.permissions() & UnveilAccess::Write)
  171. permissions_builder.append('w');
  172. if (unveiled_path.permissions() & UnveilAccess::Execute)
  173. permissions_builder.append('x');
  174. if (unveiled_path.permissions() & UnveilAccess::CreateOrRemove)
  175. permissions_builder.append('c');
  176. if (unveiled_path.permissions() & UnveilAccess::Browse)
  177. permissions_builder.append('b');
  178. TRY(obj.add("permissions", permissions_builder.string_view()));
  179. TRY(obj.finish());
  180. return IterationDecision::Continue;
  181. }));
  182. return {};
  183. }));
  184. TRY(array.finish());
  185. return {};
  186. }
  187. ErrorOr<void> Process::procfs_get_perf_events(KBufferBuilder& builder) const
  188. {
  189. InterruptDisabler disabler;
  190. if (!perf_events()) {
  191. dbgln("ProcFS: No perf events for {}", pid());
  192. return Error::from_errno(ENOBUFS);
  193. }
  194. return perf_events()->to_json(builder);
  195. }
  196. ErrorOr<void> Process::procfs_get_fds_stats(KBufferBuilder& builder) const
  197. {
  198. auto array = TRY(JsonArraySerializer<>::try_create(builder));
  199. return fds().with_shared([&](auto& fds) -> ErrorOr<void> {
  200. if (fds.open_count() == 0) {
  201. TRY(array.finish());
  202. return {};
  203. }
  204. size_t count = 0;
  205. TRY(fds.try_enumerate([&](auto& file_description_metadata) -> ErrorOr<void> {
  206. if (!file_description_metadata.is_valid()) {
  207. count++;
  208. return {};
  209. }
  210. bool cloexec = file_description_metadata.flags() & FD_CLOEXEC;
  211. RefPtr<OpenFileDescription> description = file_description_metadata.description();
  212. auto description_object = TRY(array.add_object());
  213. TRY(description_object.add("fd", count));
  214. // TODO: Better OOM handling.
  215. auto pseudo_path_or_error = description->pseudo_path();
  216. TRY(description_object.add("absolute_path", pseudo_path_or_error.is_error() ? "???"sv : pseudo_path_or_error.value()->view()));
  217. TRY(description_object.add("seekable", description->file().is_seekable()));
  218. TRY(description_object.add("class", description->file().class_name()));
  219. TRY(description_object.add("offset", description->offset()));
  220. TRY(description_object.add("cloexec", cloexec));
  221. TRY(description_object.add("blocking", description->is_blocking()));
  222. TRY(description_object.add("can_read", description->can_read()));
  223. TRY(description_object.add("can_write", description->can_write()));
  224. Inode* inode = description->inode();
  225. if (inode != nullptr) {
  226. auto inode_object = TRY(description_object.add_object("inode"));
  227. TRY(inode_object.add("fsid", inode->fsid().value()));
  228. TRY(inode_object.add("index", inode->index().value()));
  229. TRY(inode_object.finish());
  230. }
  231. TRY(description_object.finish());
  232. count++;
  233. return {};
  234. }));
  235. TRY(array.finish());
  236. return {};
  237. });
  238. }
  239. ErrorOr<void> Process::procfs_get_virtual_memory_stats(KBufferBuilder& builder) const
  240. {
  241. auto array = TRY(JsonArraySerializer<>::try_create(builder));
  242. {
  243. SpinlockLocker lock(address_space().get_lock());
  244. for (auto const& region : address_space().regions()) {
  245. if (!region.is_user() && !Process::current().is_superuser())
  246. continue;
  247. auto region_object = TRY(array.add_object());
  248. TRY(region_object.add("readable", region.is_readable()));
  249. TRY(region_object.add("writable", region.is_writable()));
  250. TRY(region_object.add("executable", region.is_executable()));
  251. TRY(region_object.add("stack", region.is_stack()));
  252. TRY(region_object.add("shared", region.is_shared()));
  253. TRY(region_object.add("syscall", region.is_syscall_region()));
  254. TRY(region_object.add("purgeable", region.vmobject().is_anonymous()));
  255. if (region.vmobject().is_anonymous()) {
  256. TRY(region_object.add("volatile", static_cast<Memory::AnonymousVMObject const&>(region.vmobject()).is_volatile()));
  257. }
  258. TRY(region_object.add("cacheable", region.is_cacheable()));
  259. TRY(region_object.add("address", region.vaddr().get()));
  260. TRY(region_object.add("size", region.size()));
  261. TRY(region_object.add("amount_resident", region.amount_resident()));
  262. TRY(region_object.add("amount_dirty", region.amount_dirty()));
  263. TRY(region_object.add("cow_pages", region.cow_pages()));
  264. TRY(region_object.add("name", region.name()));
  265. TRY(region_object.add("vmobject", region.vmobject().class_name()));
  266. StringBuilder pagemap_builder;
  267. for (size_t i = 0; i < region.page_count(); ++i) {
  268. auto const* page = region.physical_page(i);
  269. if (!page)
  270. pagemap_builder.append('N');
  271. else if (page->is_shared_zero_page() || page->is_lazy_committed_page())
  272. pagemap_builder.append('Z');
  273. else
  274. pagemap_builder.append('P');
  275. }
  276. TRY(region_object.add("pagemap", pagemap_builder.string_view()));
  277. TRY(region_object.finish());
  278. }
  279. }
  280. TRY(array.finish());
  281. return {};
  282. }
  283. ErrorOr<void> Process::procfs_get_current_work_directory_link(KBufferBuilder& builder) const
  284. {
  285. return builder.append(TRY(const_cast<Process&>(*this).current_directory()->try_serialize_absolute_path())->view());
  286. }
  287. mode_t Process::binary_link_required_mode() const
  288. {
  289. if (!executable())
  290. return 0;
  291. return m_procfs_traits->required_mode();
  292. }
  293. ErrorOr<void> Process::procfs_get_binary_link(KBufferBuilder& builder) const
  294. {
  295. auto const* custody = executable();
  296. if (!custody)
  297. return Error::from_errno(ENOEXEC);
  298. return builder.append(TRY(custody->try_serialize_absolute_path())->view());
  299. }
  300. }