1
Fork 0
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:
Ali Mohammad Pur 2022-02-14 16:49:53 +03:30 committed by Idan Horowitz
parent 80e6198563
commit a1cb2c371a
9 changed files with 145 additions and 99 deletions

View file

@ -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(); }
};
}

View file

@ -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.

View file

@ -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;

View file

@ -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 {};
}

View file

@ -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 = {};

View file

@ -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) {

View file

@ -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;