diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 4a20358817..46527b4e79 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -182,6 +182,7 @@ set(KERNEL_SOURCES ProcessExposed.cpp ProcessSpecificExposed.cpp ProcessGroup.cpp + ProcessProcFSTraits.cpp RTC.cpp Random.cpp Scheduler.cpp diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index 4a6a8a001b..cb3b587612 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -274,13 +274,15 @@ InodeMetadata ProcFSProcessDirectoryInode::metadata() const auto process = Process::from_pid(associated_pid()); if (!process) return {}; + + auto traits = process->procfs_traits(); InodeMetadata metadata; - metadata.inode = { fsid(), process->component_index() }; - metadata.mode = S_IFDIR | process->required_mode(); - metadata.uid = process->owner_user(); - metadata.gid = process->owner_group(); + metadata.inode = { fsid(), traits->component_index() }; + metadata.mode = S_IFDIR | traits->required_mode(); + metadata.uid = traits->owner_user(); + metadata.gid = traits->owner_group(); metadata.size = 0; - metadata.mtime = process->modified_time(); + metadata.mtime = traits->modified_time(); return metadata; } @@ -295,7 +297,7 @@ KResult ProcFSProcessDirectoryInode::traverse_as_directory(Functiontraverse_as_directory(procfs().fsid(), move(callback)); + return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback)); } KResultOr> ProcFSProcessDirectoryInode::lookup(StringView name) @@ -400,13 +402,15 @@ InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const auto process = Process::from_pid(associated_pid()); if (!process) return {}; + + auto traits = process->procfs_traits(); InodeMetadata metadata; - metadata.inode = { fsid(), process->component_index() }; - metadata.mode = S_IFDIR | process->required_mode(); - metadata.uid = process->owner_user(); - metadata.gid = process->owner_group(); + metadata.inode = { fsid(), traits->component_index() }; + metadata.mode = S_IFDIR | traits->required_mode(); + metadata.uid = traits->owner_user(); + metadata.gid = traits->owner_group(); metadata.size = 0; - metadata.mtime = process->modified_time(); + metadata.mtime = traits->modified_time(); return metadata; } @@ -522,13 +526,15 @@ InodeMetadata ProcFSProcessPropertyInode::metadata() const auto process = Process::from_pid(associated_pid()); if (!process) return {}; + + auto traits = process->procfs_traits(); InodeMetadata metadata; - metadata.inode = { fsid(), process->component_index() }; + metadata.inode = { fsid(), traits->component_index() }; metadata.mode = determine_procfs_process_inode_mode(m_parent_sub_directory_type, m_possible_data.property_type); - metadata.uid = process->owner_user(); - metadata.gid = process->owner_group(); + metadata.uid = traits->owner_user(); + metadata.gid = traits->owner_group(); metadata.size = 0; - metadata.mtime = process->modified_time(); + metadata.mtime = traits->modified_time(); return metadata; } KResult ProcFSProcessPropertyInode::traverse_as_directory(Function) const diff --git a/Kernel/GlobalProcessExposed.cpp b/Kernel/GlobalProcessExposed.cpp index be755db284..4d2abd4210 100644 --- a/Kernel/GlobalProcessExposed.cpp +++ b/Kernel/GlobalProcessExposed.cpp @@ -944,8 +944,9 @@ KResultOr> ProcFSRootDirectory::lookup(Str auto actual_pid = pid.value(); auto maybe_process = Process::from_pid(actual_pid); - if (maybe_process) - return maybe_process.release_nonnull(); + if (maybe_process) { + return maybe_process->procfs_traits(); + } return ENOENT; } diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 14e6c2bd64..4d9aaa18f1 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -260,6 +260,11 @@ Process::Process(const String& name, uid_t uid, gid_t gid, ProcessID ppid, bool m_protected_values.suid = uid; m_protected_values.sgid = gid; + auto maybe_procfs_traits = ProcessProcFSTraits::try_create({}, make_weak_ptr()); + // NOTE: This can fail, but it should be very, *very* rare. + VERIFY(!maybe_procfs_traits.is_error()); + m_procfs_traits = maybe_procfs_traits.release_value(); + dbgln_if(PROCESS_DEBUG, "Created new process {}({})", m_name, this->pid().value()); } diff --git a/Kernel/Process.h b/Kernel/Process.h index a9a0e0953a..4373c530f7 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -85,10 +85,9 @@ typedef HashMap> FutexQueues; struct LoadResult; class Process - : public ProcFSExposedComponent + : public RefCounted , public Weakable { -private: class ProtectedValues { public: ProcessID pid { 0 }; @@ -145,6 +144,8 @@ public: }; public: + class ProcessProcFSTraits; + inline static Process* current() { auto current_thread = Processor::current_thread(); @@ -549,13 +550,7 @@ private: void setup_socket_fd(int fd, NonnullRefPtr description, int type); public: - // ^ProcFSExposedComponent stats - virtual InodeIndex component_index() const override; - virtual KResultOr> to_inode(const ProcFS& procfs_instance) const override; - virtual KResult traverse_as_directory(unsigned, Function) const override; - virtual mode_t required_mode() const override { return 0555; } - virtual uid_t owner_user() const override { return uid(); } - virtual gid_t owner_group() const override { return gid(); } + NonnullRefPtr procfs_traits() const { return *m_procfs_traits; } KResult procfs_get_fds_stats(KBufferBuilder& builder) const; KResult procfs_get_perf_events(KBufferBuilder& builder) const; KResult procfs_get_unveil_stats(KBufferBuilder& builder) const; @@ -713,6 +708,37 @@ public: FileDescriptionAndFlags* m_description { nullptr }; }; + class ProcessProcFSTraits : public ProcFSExposedComponent { + public: + static KResultOr> try_create(Badge, WeakPtr process) + { + auto result = adopt_ref_if_nonnull(new (nothrow) ProcessProcFSTraits(process)); + if (!result) + return ENOMEM; + + return result.release_nonnull(); + } + + virtual InodeIndex component_index() const override; + virtual KResultOr> to_inode(const ProcFS& procfs_instance) const override; + virtual KResult traverse_as_directory(unsigned, Function) const override; + virtual mode_t required_mode() const override { return 0555; } + + virtual uid_t owner_user() const override; + + virtual gid_t owner_group() const override; + + private: + ProcessProcFSTraits(WeakPtr process) + : m_process(process) + { + } + + // NOTE: We need to weakly hold on to the process, because otherwise + // we would be creating a reference cycle. + WeakPtr m_process; + }; + FileDescriptions& fds() { return m_fds; } const FileDescriptions& fds() const { return m_fds; } @@ -770,9 +796,10 @@ private: }; Array m_coredump_properties; - NonnullRefPtrVector m_threads_for_coredump; + mutable RefPtr m_procfs_traits; + static_assert(sizeof(ProtectedValues) < (PAGE_SIZE)); alignas(4096) ProtectedValues m_protected_values; u8 m_protected_values_padding[PAGE_SIZE - sizeof(ProtectedValues)]; diff --git a/Kernel/ProcessProcFSTraits.cpp b/Kernel/ProcessProcFSTraits.cpp new file mode 100644 index 0000000000..8e8a018974 --- /dev/null +++ b/Kernel/ProcessProcFSTraits.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021, sin-ack + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Kernel { + +uid_t Process::ProcessProcFSTraits::owner_user() const +{ + auto process = m_process.strong_ref(); + if (!process) + return 0; + + return process->uid(); +} + +gid_t Process::ProcessProcFSTraits::owner_group() const +{ + auto process = m_process.strong_ref(); + if (!process) + return 0; + + return process->gid(); +} + +InodeIndex Process::ProcessProcFSTraits::component_index() const +{ + auto process = m_process.strong_ref(); + if (!process) + return {}; + + return SegmentedProcFSIndex::build_segmented_index_for_pid_directory(process->pid()); +} + +KResultOr> Process::ProcessProcFSTraits::to_inode(const ProcFS& procfs_instance) const +{ + auto process = m_process.strong_ref(); + if (!process) + return ESRCH; + + auto maybe_inode = ProcFSProcessDirectoryInode::try_create(procfs_instance, process->pid()); + if (maybe_inode.is_error()) + return maybe_inode.error(); + return maybe_inode.release_value(); +} + +KResult Process::ProcessProcFSTraits::traverse_as_directory(unsigned fsid, Function callback) const +{ + auto process = m_process.strong_ref(); + if (!process) + return ESRCH; + + callback({ ".", { fsid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(process->pid()) }, 0 }); + callback({ "..", { fsid, ProcFSComponentRegistry::the().root_directory().component_index() }, 0 }); + callback({ "fd", { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(process->pid(), SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions) }, 0 }); + callback({ "stacks", { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(process->pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks) }, 0 }); + callback({ "unveil", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::Unveil) }, 0 }); + callback({ "pledge", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::Pledge) }, 0 }); + callback({ "fds", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::FileDescriptions) }, 0 }); + callback({ "exe", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink) }, 0 }); + callback({ "cwd", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink) }, 0 }); + callback({ "perf_events", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents) }, 0 }); + callback({ "vm", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats) }, 0 }); + callback({ "root", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::RootLink) }, 0 }); + return KSuccess; +} + +} diff --git a/Kernel/ProcessSpecificExposed.cpp b/Kernel/ProcessSpecificExposed.cpp index 00689f867e..e42a2adbe3 100644 --- a/Kernel/ProcessSpecificExposed.cpp +++ b/Kernel/ProcessSpecificExposed.cpp @@ -40,40 +40,10 @@ KResultOr Process::procfs_get_thread_stack(ThreadID thread_id, KBufferBu return KSuccess; } -InodeIndex Process::component_index() const -{ - return SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid()); -} - -KResultOr> Process::to_inode(const ProcFS& procfs_instance) const -{ - auto maybe_inode = ProcFSProcessDirectoryInode::try_create(procfs_instance, m_protected_values.pid); - if (maybe_inode.is_error()) - return maybe_inode.error(); - return maybe_inode.release_value(); -} - -KResult Process::traverse_as_directory(unsigned fsid, Function callback) const -{ - callback({ ".", { fsid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid()) }, 0 }); - callback({ "..", { fsid, ProcFSComponentRegistry::the().root_directory().component_index() }, 0 }); - callback({ "fd", { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid(), SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions) }, 0 }); - callback({ "stacks", { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks) }, 0 }); - callback({ "unveil", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::Unveil) }, 0 }); - callback({ "pledge", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::Pledge) }, 0 }); - callback({ "fds", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::FileDescriptions) }, 0 }); - callback({ "exe", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink) }, 0 }); - callback({ "cwd", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink) }, 0 }); - callback({ "perf_events", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents) }, 0 }); - callback({ "vm", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats) }, 0 }); - callback({ "root", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::RootLink) }, 0 }); - return KSuccess; -} - KResult Process::traverse_stacks_directory(unsigned fsid, Function callback) const { callback({ ".", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, SegmentedProcFSIndex::MainProcessProperty::Reserved) }, 0 }); - callback({ "..", { fsid, component_index() }, 0 }); + callback({ "..", { fsid, m_procfs_traits->component_index() }, 0 }); for_each_thread([&](const Thread& thread) { int tid = thread.tid().value(); @@ -119,8 +89,8 @@ KResultOr Process::procfs_get_file_description_link(unsigned fd, KBuffer KResult Process::traverse_file_descriptions_directory(unsigned fsid, Function callback) const { - callback({ ".", { fsid, component_index() }, 0 }); - callback({ "..", { fsid, component_index() }, 0 }); + callback({ ".", { fsid, m_procfs_traits->component_index() }, 0 }); + callback({ "..", { fsid, m_procfs_traits->component_index() }, 0 }); size_t count = 0; fds().enumerate([&](auto& file_description_metadata) { if (!file_description_metadata.is_valid()) { @@ -309,7 +279,7 @@ mode_t Process::binary_link_required_mode() const { if (!executable()) return 0; - return ProcFSExposedComponent::required_mode(); + return m_procfs_traits->required_mode(); } KResult Process::procfs_get_binary_link(KBufferBuilder& builder) const