ProcessExposed.cpp 17 KB

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