ProcessSpecificExposed.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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/x86/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<size_t> Process::procfs_get_thread_stack(ThreadID thread_id, KBufferBuilder& builder) const
  20. {
  21. JsonArraySerializer array { builder };
  22. auto thread = Thread::from_tid(thread_id);
  23. if (!thread)
  24. return Error::from_errno(ESRCH);
  25. bool show_kernel_addresses = Process::current().is_superuser();
  26. bool kernel_address_added = false;
  27. for (auto address : 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. array.add(address);
  35. }
  36. array.finish();
  37. // FIXME: This return value seems useless.
  38. return 0;
  39. }
  40. ErrorOr<void> Process::traverse_stacks_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
  41. {
  42. TRY(callback({ ".", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, SegmentedProcFSIndex::MainProcessProperty::Reserved) }, 0 }));
  43. TRY(callback({ "..", { fsid, m_procfs_traits->component_index() }, 0 }));
  44. return thread_list().with([&](auto& list) -> ErrorOr<void> {
  45. for (auto const& thread : list) {
  46. int tid = thread.tid().value();
  47. InodeIdentifier identifier = { fsid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid(), thread.tid()) };
  48. TRY(callback({ String::number(tid), identifier, 0 }));
  49. }
  50. return {};
  51. });
  52. }
  53. ErrorOr<NonnullRefPtr<Inode>> Process::lookup_stacks_directory(const ProcFS& procfs, StringView name) const
  54. {
  55. ErrorOr<NonnullRefPtr<ProcFSProcessPropertyInode>> thread_stack_inode { ENOENT };
  56. // FIXME: Try to exit the loop earlier
  57. for_each_thread([&](const Thread& thread) {
  58. int tid = thread.tid().value();
  59. VERIFY(!(tid < 0));
  60. if (name.to_int() == tid) {
  61. auto maybe_inode = ProcFSProcessPropertyInode::try_create_for_thread_stack(procfs, thread.tid(), pid());
  62. if (maybe_inode.is_error()) {
  63. thread_stack_inode = maybe_inode.release_error();
  64. return;
  65. }
  66. thread_stack_inode = maybe_inode.release_value();
  67. }
  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<size_t> Process::procfs_get_file_description_link(unsigned fd, KBufferBuilder& builder) const
  74. {
  75. auto file_description = TRY(m_fds.open_file_description(fd));
  76. // Note: These links are not guaranteed to point to actual VFS paths, just like in other kernels.
  77. auto data = TRY(file_description->pseudo_path());
  78. TRY(builder.append(data->view()));
  79. return data->length();
  80. }
  81. ErrorOr<void> Process::traverse_file_descriptions_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
  82. {
  83. TRY(callback({ ".", { fsid, m_procfs_traits->component_index() }, 0 }));
  84. TRY(callback({ "..", { fsid, m_procfs_traits->component_index() }, 0 }));
  85. size_t count = 0;
  86. fds().enumerate([&](auto& file_description_metadata) {
  87. if (!file_description_metadata.is_valid()) {
  88. count++;
  89. return;
  90. }
  91. StringBuilder builder;
  92. builder.appendff("{}", count);
  93. // FIXME: Propagate errors from callback.
  94. (void)callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid(), count) }, DT_LNK });
  95. count++;
  96. });
  97. return {};
  98. }
  99. ErrorOr<NonnullRefPtr<Inode>> Process::lookup_file_descriptions_directory(const ProcFS& procfs, StringView name) const
  100. {
  101. auto maybe_index = name.to_uint();
  102. if (!maybe_index.has_value())
  103. return ENOENT;
  104. if (!fds().get_if_valid(*maybe_index))
  105. return ENOENT;
  106. return TRY(ProcFSProcessPropertyInode::try_create_for_file_description_link(procfs, *maybe_index, pid()));
  107. }
  108. ErrorOr<void> Process::procfs_get_pledge_stats(KBufferBuilder& builder) const
  109. {
  110. JsonObjectSerializer obj { builder };
  111. #define __ENUMERATE_PLEDGE_PROMISE(x) \
  112. if (has_promised(Pledge::x)) { \
  113. if (!builder.is_empty()) \
  114. builder.append(' '); \
  115. builder.append(#x); \
  116. }
  117. if (has_promises()) {
  118. StringBuilder builder;
  119. ENUMERATE_PLEDGE_PROMISES
  120. obj.add("promises", builder.build());
  121. }
  122. #undef __ENUMERATE_PLEDGE_PROMISE
  123. obj.finish();
  124. return {};
  125. }
  126. ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
  127. {
  128. JsonArraySerializer array { builder };
  129. for (auto& unveiled_path : unveiled_paths()) {
  130. if (!unveiled_path.was_explicitly_unveiled())
  131. continue;
  132. auto obj = array.add_object();
  133. obj.add("path", unveiled_path.path());
  134. StringBuilder permissions_builder;
  135. if (unveiled_path.permissions() & UnveilAccess::Read)
  136. permissions_builder.append('r');
  137. if (unveiled_path.permissions() & UnveilAccess::Write)
  138. permissions_builder.append('w');
  139. if (unveiled_path.permissions() & UnveilAccess::Execute)
  140. permissions_builder.append('x');
  141. if (unveiled_path.permissions() & UnveilAccess::CreateOrRemove)
  142. permissions_builder.append('c');
  143. if (unveiled_path.permissions() & UnveilAccess::Browse)
  144. permissions_builder.append('b');
  145. obj.add("permissions", permissions_builder.string_view());
  146. }
  147. array.finish();
  148. return {};
  149. }
  150. ErrorOr<void> Process::procfs_get_perf_events(KBufferBuilder& builder) const
  151. {
  152. InterruptDisabler disabler;
  153. if (!perf_events()) {
  154. dbgln("ProcFS: No perf events for {}", pid());
  155. return Error::from_errno(ENOBUFS);
  156. }
  157. return perf_events()->to_json(builder);
  158. }
  159. ErrorOr<void> Process::procfs_get_fds_stats(KBufferBuilder& builder) const
  160. {
  161. JsonArraySerializer array { builder };
  162. if (fds().open_count() == 0) {
  163. array.finish();
  164. return {};
  165. }
  166. size_t count = 0;
  167. fds().enumerate([&](auto& file_description_metadata) {
  168. if (!file_description_metadata.is_valid()) {
  169. count++;
  170. return;
  171. }
  172. bool cloexec = file_description_metadata.flags() & FD_CLOEXEC;
  173. RefPtr<OpenFileDescription> description = file_description_metadata.description();
  174. auto description_object = array.add_object();
  175. description_object.add("fd", count);
  176. // TODO: Better OOM handling.
  177. auto pseudo_path_or_error = description->pseudo_path();
  178. description_object.add("absolute_path", pseudo_path_or_error.is_error() ? "???"sv : pseudo_path_or_error.value()->view());
  179. description_object.add("seekable", description->file().is_seekable());
  180. description_object.add("class", description->file().class_name());
  181. description_object.add("offset", description->offset());
  182. description_object.add("cloexec", cloexec);
  183. description_object.add("blocking", description->is_blocking());
  184. description_object.add("can_read", description->can_read());
  185. description_object.add("can_write", description->can_write());
  186. Inode* inode = description->inode();
  187. if (inode != nullptr) {
  188. auto inode_object = description_object.add_object("inode");
  189. inode_object.add("fsid", inode->fsid().value());
  190. inode_object.add("index", inode->index().value());
  191. inode_object.finish();
  192. }
  193. count++;
  194. });
  195. array.finish();
  196. return {};
  197. }
  198. ErrorOr<void> Process::procfs_get_virtual_memory_stats(KBufferBuilder& builder) const
  199. {
  200. JsonArraySerializer array { builder };
  201. {
  202. SpinlockLocker lock(address_space().get_lock());
  203. for (auto& region : address_space().regions()) {
  204. if (!region->is_user() && !Process::current().is_superuser())
  205. continue;
  206. auto region_object = array.add_object();
  207. region_object.add("readable", region->is_readable());
  208. region_object.add("writable", region->is_writable());
  209. region_object.add("executable", region->is_executable());
  210. region_object.add("stack", region->is_stack());
  211. region_object.add("shared", region->is_shared());
  212. region_object.add("syscall", region->is_syscall_region());
  213. region_object.add("purgeable", region->vmobject().is_anonymous());
  214. if (region->vmobject().is_anonymous()) {
  215. region_object.add("volatile", static_cast<Memory::AnonymousVMObject const&>(region->vmobject()).is_volatile());
  216. }
  217. region_object.add("cacheable", region->is_cacheable());
  218. region_object.add("address", region->vaddr().get());
  219. region_object.add("size", region->size());
  220. region_object.add("amount_resident", region->amount_resident());
  221. region_object.add("amount_dirty", region->amount_dirty());
  222. region_object.add("cow_pages", region->cow_pages());
  223. region_object.add("name", region->name());
  224. region_object.add("vmobject", region->vmobject().class_name());
  225. StringBuilder pagemap_builder;
  226. for (size_t i = 0; i < region->page_count(); ++i) {
  227. auto* page = region->physical_page(i);
  228. if (!page)
  229. pagemap_builder.append('N');
  230. else if (page->is_shared_zero_page() || page->is_lazy_committed_page())
  231. pagemap_builder.append('Z');
  232. else
  233. pagemap_builder.append('P');
  234. }
  235. region_object.add("pagemap", pagemap_builder.string_view());
  236. }
  237. }
  238. array.finish();
  239. return {};
  240. }
  241. ErrorOr<void> Process::procfs_get_current_work_directory_link(KBufferBuilder& builder) const
  242. {
  243. return builder.append_bytes(const_cast<Process&>(*this).current_directory().absolute_path().bytes());
  244. }
  245. mode_t Process::binary_link_required_mode() const
  246. {
  247. if (!executable())
  248. return 0;
  249. return m_procfs_traits->required_mode();
  250. }
  251. ErrorOr<void> Process::procfs_get_binary_link(KBufferBuilder& builder) const
  252. {
  253. auto* custody = executable();
  254. if (!custody)
  255. return Error::from_errno(ENOEXEC);
  256. return builder.append(custody->absolute_path().bytes());
  257. }
  258. ErrorOr<void> Process::procfs_get_tty_link(KBufferBuilder& builder) const
  259. {
  260. if (m_tty.is_null())
  261. return Error::from_errno(ENOENT);
  262. return builder.append(m_tty->tty_name().view());
  263. }
  264. }