mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 14:37:43 +00:00
Kernel: Put Process unveil state in a SpinlockProtected container
This makes path resolution safe to perform without holding the big lock.
This commit is contained in:
parent
24f02bd421
commit
580d89f093
7 changed files with 87 additions and 67 deletions
|
@ -748,10 +748,10 @@ UnveilNode const& VirtualFileSystem::find_matching_unveiled_path(StringView path
|
||||||
{
|
{
|
||||||
auto& current_process = Process::current();
|
auto& current_process = Process::current();
|
||||||
VERIFY(current_process.veil_state() != VeilState::None);
|
VERIFY(current_process.veil_state() != VeilState::None);
|
||||||
auto& unveil_root = current_process.unveiled_paths();
|
return current_process.unveil_data().with([&](auto const& unveil_data) -> UnveilNode const& {
|
||||||
|
|
||||||
auto path_parts = KLexicalPath::parts(path);
|
auto path_parts = KLexicalPath::parts(path);
|
||||||
return unveil_root.traverse_until_last_accessible_node(path_parts.begin(), path_parts.end());
|
return unveil_data.paths.traverse_until_last_accessible_node(path_parts.begin(), path_parts.end());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> VirtualFileSystem::validate_path_against_process_veil(Custody const& custody, int options)
|
ErrorOr<void> VirtualFileSystem::validate_path_against_process_veil(Custody const& custody, int options)
|
||||||
|
|
|
@ -224,13 +224,13 @@ ErrorOr<NonnullRefPtr<Process>> Process::try_create(RefPtr<Thread>& first_thread
|
||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
Process::Process(NonnullOwnPtr<KString> name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, UnveilNode unveil_tree)
|
Process::Process(NonnullOwnPtr<KString> name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, UnveilNode unveil_tree)
|
||||||
: m_name(move(name))
|
: m_name(move(name))
|
||||||
, m_is_kernel_process(is_kernel_process)
|
, m_is_kernel_process(is_kernel_process)
|
||||||
, m_executable(move(executable))
|
, m_executable(move(executable))
|
||||||
, m_current_directory(move(current_directory))
|
, m_current_directory(move(current_directory))
|
||||||
, m_tty(tty)
|
, m_tty(tty)
|
||||||
, m_unveiled_paths(move(unveil_tree))
|
, m_unveil_data(move(unveil_tree))
|
||||||
, m_wait_blocker_set(*this)
|
, m_wait_blocker_set(*this)
|
||||||
{
|
{
|
||||||
// Ensure that we protect the process data when exiting the constructor.
|
// Ensure that we protect the process data when exiting the constructor.
|
||||||
|
|
|
@ -466,12 +466,20 @@ public:
|
||||||
|
|
||||||
VeilState veil_state() const
|
VeilState veil_state() const
|
||||||
{
|
{
|
||||||
return m_veil_state;
|
return m_unveil_data.with([&](auto const& unveil_data) { return unveil_data.state; });
|
||||||
}
|
}
|
||||||
const UnveilNode& unveiled_paths() const
|
|
||||||
|
struct UnveilData {
|
||||||
|
explicit UnveilData(UnveilNode&& p)
|
||||||
|
: paths(move(p))
|
||||||
{
|
{
|
||||||
return m_unveiled_paths;
|
|
||||||
}
|
}
|
||||||
|
VeilState state { VeilState::None };
|
||||||
|
UnveilNode paths;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto& unveil_data() { return m_unveil_data; }
|
||||||
|
auto const& unveil_data() const { return m_unveil_data; }
|
||||||
|
|
||||||
bool wait_for_tracer_at_next_execve() const
|
bool wait_for_tracer_at_next_execve() const
|
||||||
{
|
{
|
||||||
|
@ -805,8 +813,7 @@ private:
|
||||||
|
|
||||||
RefPtr<Timer> m_alarm_timer;
|
RefPtr<Timer> m_alarm_timer;
|
||||||
|
|
||||||
VeilState m_veil_state { VeilState::None };
|
SpinlockProtected<UnveilData> m_unveil_data;
|
||||||
UnveilNode m_unveiled_paths;
|
|
||||||
|
|
||||||
OwnPtr<PerformanceEventBuffer> m_perf_event_buffer;
|
OwnPtr<PerformanceEventBuffer> m_perf_event_buffer;
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,8 @@ ErrorOr<void> Process::procfs_get_pledge_stats(KBufferBuilder& builder) const
|
||||||
ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
|
ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
|
||||||
{
|
{
|
||||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||||
TRY(unveiled_paths().for_each_node_in_tree_order([&](auto const& unveiled_path) -> ErrorOr<IterationDecision> {
|
TRY(m_unveil_data.with([&](auto& unveil_data) -> ErrorOr<void> {
|
||||||
|
TRY(unveil_data.paths.for_each_node_in_tree_order([&](auto const& unveiled_path) -> ErrorOr<IterationDecision> {
|
||||||
if (!unveiled_path.was_explicitly_unveiled())
|
if (!unveiled_path.was_explicitly_unveiled())
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
auto obj = TRY(array.add_object());
|
auto obj = TRY(array.add_object());
|
||||||
|
@ -165,6 +166,8 @@ ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
|
||||||
TRY(obj.finish());
|
TRY(obj.finish());
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
}));
|
}));
|
||||||
|
return {};
|
||||||
|
}));
|
||||||
TRY(array.finish());
|
TRY(array.finish());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -523,9 +523,12 @@ ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_d
|
||||||
m_arguments = move(arguments);
|
m_arguments = move(arguments);
|
||||||
m_environment = move(environment);
|
m_environment = move(environment);
|
||||||
|
|
||||||
m_veil_state = VeilState::None;
|
TRY(m_unveil_data.with([&](auto& unveil_data) -> ErrorOr<void> {
|
||||||
m_unveiled_paths.clear();
|
unveil_data.state = VeilState::None;
|
||||||
m_unveiled_paths.set_metadata({ TRY(KString::try_create("/"sv)), UnveilAccess::None, false });
|
unveil_data.paths.clear();
|
||||||
|
unveil_data.paths.set_metadata({ TRY(KString::try_create("/"sv)), UnveilAccess::None, false });
|
||||||
|
return {};
|
||||||
|
}));
|
||||||
|
|
||||||
for (auto& property : m_coredump_properties)
|
for (auto& property : m_coredump_properties)
|
||||||
property = {};
|
property = {};
|
||||||
|
|
|
@ -20,8 +20,13 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs)
|
||||||
RefPtr<Thread> child_first_thread;
|
RefPtr<Thread> child_first_thread;
|
||||||
auto child_name = TRY(m_name->try_clone());
|
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, current_directory(), m_executable, m_tty, this));
|
auto child = TRY(Process::try_create(child_first_thread, move(child_name), uid(), gid(), pid(), m_is_kernel_process, current_directory(), m_executable, m_tty, this));
|
||||||
child->m_veil_state = m_veil_state;
|
TRY(m_unveil_data.with([&](auto& parent_unveil_data) -> ErrorOr<void> {
|
||||||
child->m_unveiled_paths = TRY(m_unveiled_paths.deep_copy());
|
return child->m_unveil_data.with([&](auto& child_unveil_data) -> ErrorOr<void> {
|
||||||
|
child_unveil_data.state = parent_unveil_data.state;
|
||||||
|
child_unveil_data.paths = TRY(parent_unveil_data.paths.deep_copy());
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
TRY(child->m_fds.with_exclusive([&](auto& child_fds) {
|
TRY(child->m_fds.with_exclusive([&](auto& child_fds) {
|
||||||
return m_fds.with_exclusive([&](auto& parent_fds) {
|
return m_fds.with_exclusive([&](auto& parent_fds) {
|
||||||
|
|
|
@ -30,11 +30,11 @@ ErrorOr<FlatPtr> Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*>
|
||||||
auto params = TRY(copy_typed_from_user(user_params));
|
auto params = TRY(copy_typed_from_user(user_params));
|
||||||
|
|
||||||
if (!params.path.characters && !params.permissions.characters) {
|
if (!params.path.characters && !params.permissions.characters) {
|
||||||
m_veil_state = VeilState::Locked;
|
m_unveil_data.with([&](auto& unveil_data) { unveil_data.state = VeilState::Locked; });
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_veil_state == VeilState::Locked)
|
if (veil_state() == VeilState::Locked)
|
||||||
return EPERM;
|
return EPERM;
|
||||||
|
|
||||||
if (!params.path.characters || !params.permissions.characters)
|
if (!params.path.characters || !params.permissions.characters)
|
||||||
|
@ -94,7 +94,8 @@ ErrorOr<FlatPtr> Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*>
|
||||||
|
|
||||||
auto path_parts = KLexicalPath::parts(new_unveiled_path->view());
|
auto path_parts = KLexicalPath::parts(new_unveiled_path->view());
|
||||||
auto it = path_parts.begin();
|
auto it = path_parts.begin();
|
||||||
auto& matching_node = m_unveiled_paths.traverse_until_last_accessible_node(it, path_parts.end());
|
return m_unveil_data.with([&](auto& unveil_data) -> ErrorOr<FlatPtr> {
|
||||||
|
auto& matching_node = unveil_data.paths.traverse_until_last_accessible_node(it, path_parts.end());
|
||||||
if (it.is_end()) {
|
if (it.is_end()) {
|
||||||
// If the path has already been explicitly unveiled, do not allow elevating its permissions.
|
// If the path has already been explicitly unveiled, do not allow elevating its permissions.
|
||||||
if (matching_node.was_explicitly_unveiled()) {
|
if (matching_node.was_explicitly_unveiled()) {
|
||||||
|
@ -111,7 +112,7 @@ ErrorOr<FlatPtr> Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*>
|
||||||
|
|
||||||
matching_node.metadata_value().explicitly_unveiled = true;
|
matching_node.metadata_value().explicitly_unveiled = true;
|
||||||
matching_node.metadata_value().permissions = (UnveilAccess)new_permissions;
|
matching_node.metadata_value().permissions = (UnveilAccess)new_permissions;
|
||||||
m_veil_state = VeilState::Dropped;
|
unveil_data.state = VeilState::Dropped;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,9 +125,10 @@ ErrorOr<FlatPtr> Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*>
|
||||||
return UnveilMetadata(move(path), parent.permissions(), false);
|
return UnveilMetadata(move(path), parent.permissions(), false);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
VERIFY(m_veil_state != VeilState::Locked);
|
VERIFY(unveil_data.state != VeilState::Locked);
|
||||||
m_veil_state = VeilState::Dropped;
|
unveil_data.state = VeilState::Dropped;
|
||||||
return 0;
|
return 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue