ProcessSpecificExposed.cpp 14 KB

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