mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 21:27:45 +00:00
AK+Kernel: OOM-harden most parts of Trie
The only part of Unveil that can't handle OOM gracefully is the String::formatted() use in the node metadata.
This commit is contained in:
parent
80e6198563
commit
a1cb2c371a
9 changed files with 145 additions and 99 deletions
|
@ -24,9 +24,29 @@ enum UnveilAccess {
|
|||
struct UnveilNode;
|
||||
|
||||
struct UnveilMetadata {
|
||||
String full_path;
|
||||
NonnullOwnPtr<KString> full_path;
|
||||
UnveilAccess permissions { None };
|
||||
bool explicitly_unveiled { false };
|
||||
|
||||
UnveilMetadata(UnveilMetadata const&) = delete;
|
||||
UnveilMetadata(UnveilMetadata&&) = default;
|
||||
|
||||
// Note: Intentionally not explicit.
|
||||
UnveilMetadata(NonnullOwnPtr<KString>&& full_path, UnveilAccess permissions = None, bool explicitly_unveiled = false)
|
||||
: full_path(move(full_path))
|
||||
, permissions(permissions)
|
||||
, explicitly_unveiled(explicitly_unveiled)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorOr<UnveilMetadata> copy() const
|
||||
{
|
||||
return UnveilMetadata {
|
||||
TRY(full_path->try_clone()),
|
||||
permissions,
|
||||
explicitly_unveiled,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct UnveilNode final : public Trie<String, UnveilMetadata, Traits<String>, UnveilNode> {
|
||||
|
@ -34,7 +54,7 @@ struct UnveilNode final : public Trie<String, UnveilMetadata, Traits<String>, Un
|
|||
|
||||
bool was_explicitly_unveiled() const { return this->metadata_value().explicitly_unveiled; }
|
||||
UnveilAccess permissions() const { return this->metadata_value().permissions; }
|
||||
const String& path() const { return this->metadata_value().full_path; }
|
||||
StringView path() const { return this->metadata_value().full_path->view(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -218,17 +218,18 @@ void Process::unprotect_data()
|
|||
ErrorOr<NonnullRefPtr<Process>> Process::try_create(RefPtr<Thread>& first_thread, NonnullOwnPtr<KString> name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> cwd, RefPtr<Custody> executable, TTY* tty, Process* fork_parent)
|
||||
{
|
||||
auto space = TRY(Memory::AddressSpace::try_create(fork_parent ? &fork_parent->address_space() : nullptr));
|
||||
auto process = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Process(move(name), uid, gid, ppid, is_kernel_process, move(cwd), move(executable), tty)));
|
||||
auto process = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Process(move(name), uid, gid, ppid, is_kernel_process, move(cwd), move(executable), tty, UnveilNode { "/"sv, UnveilMetadata(TRY(KString::try_create("/"sv))) })));
|
||||
TRY(process->attach_resources(move(space), first_thread, fork_parent));
|
||||
return process;
|
||||
}
|
||||
|
||||
Process::Process(NonnullOwnPtr<KString> name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> cwd, RefPtr<Custody> executable, TTY* tty)
|
||||
Process::Process(NonnullOwnPtr<KString> name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> cwd, RefPtr<Custody> executable, TTY* tty, UnveilNode unveil_tree)
|
||||
: m_name(move(name))
|
||||
, m_is_kernel_process(is_kernel_process)
|
||||
, m_executable(move(executable))
|
||||
, m_cwd(move(cwd))
|
||||
, m_tty(tty)
|
||||
, m_unveiled_paths(move(unveil_tree))
|
||||
, m_wait_blocker_set(*this)
|
||||
{
|
||||
// Ensure that we protect the process data when exiting the constructor.
|
||||
|
|
|
@ -521,7 +521,7 @@ private:
|
|||
bool add_thread(Thread&);
|
||||
bool remove_thread(Thread&);
|
||||
|
||||
Process(NonnullOwnPtr<KString> name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> cwd, RefPtr<Custody> executable, TTY* tty);
|
||||
Process(NonnullOwnPtr<KString> name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> cwd, RefPtr<Custody> executable, TTY* tty, UnveilNode unveil_tree);
|
||||
static ErrorOr<NonnullRefPtr<Process>> try_create(RefPtr<Thread>& first_thread, NonnullOwnPtr<KString> name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> cwd = nullptr, RefPtr<Custody> executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr);
|
||||
ErrorOr<void> attach_resources(NonnullOwnPtr<Memory::AddressSpace>&&, RefPtr<Thread>& first_thread, Process* fork_parent);
|
||||
static ProcessID allocate_pid();
|
||||
|
@ -800,7 +800,7 @@ private:
|
|||
RefPtr<Timer> m_alarm_timer;
|
||||
|
||||
VeilState m_veil_state { VeilState::None };
|
||||
UnveilNode m_unveiled_paths { "/", { .full_path = "/" } };
|
||||
UnveilNode m_unveiled_paths;
|
||||
|
||||
OwnPtr<PerformanceEventBuffer> m_perf_event_buffer;
|
||||
|
||||
|
|
|
@ -145,9 +145,9 @@ ErrorOr<void> Process::procfs_get_pledge_stats(KBufferBuilder& builder) const
|
|||
ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
for (auto const& unveiled_path : unveiled_paths()) {
|
||||
TRY(unveiled_paths().for_each_node_in_tree_order([&](auto const& unveiled_path) {
|
||||
if (!unveiled_path.was_explicitly_unveiled())
|
||||
continue;
|
||||
return;
|
||||
auto obj = array.add_object();
|
||||
obj.add("path", unveiled_path.path());
|
||||
StringBuilder permissions_builder;
|
||||
|
@ -162,7 +162,7 @@ ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
|
|||
if (unveiled_path.permissions() & UnveilAccess::Browse)
|
||||
permissions_builder.append('b');
|
||||
obj.add("permissions", permissions_builder.string_view());
|
||||
}
|
||||
}));
|
||||
array.finish();
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -525,7 +525,7 @@ ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_d
|
|||
|
||||
m_veil_state = VeilState::None;
|
||||
m_unveiled_paths.clear();
|
||||
m_unveiled_paths.set_metadata({ "/", UnveilAccess::None, false });
|
||||
m_unveiled_paths.set_metadata({ TRY(KString::try_create("/"sv)), UnveilAccess::None, false });
|
||||
|
||||
for (auto& property : m_coredump_properties)
|
||||
property = {};
|
||||
|
|
|
@ -21,7 +21,7 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs)
|
|||
auto child_name = TRY(m_name->try_clone());
|
||||
auto child = TRY(Process::try_create(child_first_thread, move(child_name), uid(), gid(), pid(), m_is_kernel_process, m_cwd, m_executable, m_tty, this));
|
||||
child->m_veil_state = m_veil_state;
|
||||
child->m_unveiled_paths = m_unveiled_paths.deep_copy();
|
||||
child->m_unveiled_paths = TRY(m_unveiled_paths.deep_copy());
|
||||
|
||||
TRY(child->m_fds.with_exclusive([&](auto& child_fds) {
|
||||
return m_fds.with_exclusive([&](auto& parent_fds) {
|
||||
|
|
|
@ -19,7 +19,7 @@ static void update_intermediate_node_permissions(UnveilNode& root_node, UnveilAc
|
|||
auto& node = static_cast<UnveilNode&>(*entry.value);
|
||||
if (node.was_explicitly_unveiled())
|
||||
continue;
|
||||
node.set_metadata({ node.path(), new_permissions, node.was_explicitly_unveiled() });
|
||||
node.metadata_value().permissions = new_permissions;
|
||||
update_intermediate_node_permissions(node, new_permissions);
|
||||
}
|
||||
}
|
||||
|
@ -109,19 +109,20 @@ ErrorOr<FlatPtr> Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*>
|
|||
if (matching_node.permissions() != new_permissions)
|
||||
update_intermediate_node_permissions(matching_node, (UnveilAccess)new_permissions);
|
||||
|
||||
matching_node.set_metadata({ matching_node.path(), (UnveilAccess)new_permissions, true });
|
||||
matching_node.metadata_value().explicitly_unveiled = true;
|
||||
matching_node.metadata_value().permissions = (UnveilAccess)new_permissions;
|
||||
m_veil_state = VeilState::Dropped;
|
||||
return 0;
|
||||
}
|
||||
|
||||
matching_node.insert(
|
||||
TRY(matching_node.insert(
|
||||
it,
|
||||
path_parts.end(),
|
||||
{ new_unveiled_path->view(), (UnveilAccess)new_permissions, true },
|
||||
[](auto& parent, auto& it) -> Optional<UnveilMetadata> {
|
||||
auto path = String::formatted("{}/{}", parent.path(), *it);
|
||||
return UnveilMetadata { path, parent.permissions(), false };
|
||||
});
|
||||
{ new_unveiled_path.release_nonnull(), (UnveilAccess)new_permissions, true },
|
||||
[](auto& parent, auto& it) -> ErrorOr<Optional<UnveilMetadata>> {
|
||||
auto path = TRY(KString::formatted("{}/{}", parent.path(), *it));
|
||||
return UnveilMetadata(move(path), parent.permissions(), false);
|
||||
}));
|
||||
|
||||
VERIFY(m_veil_state != VeilState::Locked);
|
||||
m_veil_state = VeilState::Dropped;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue