From f12d81ddf5ef3efd8c8cf8c5abdf13f667288067 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Fri, 25 Mar 2022 01:19:48 +0430 Subject: [PATCH] Shell: Limit the access of processes spawned for autocompletion This commit limits the autocomplete processes to effectively have readonly access to the fs, and only enough pledges to get the dynamic loader working. --- Userland/Shell/Shell.cpp | 15 +++++++++++++++ Userland/Shell/Shell.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/Userland/Shell/Shell.cpp b/Userland/Shell/Shell.cpp index 6fb09d88aa..f5f480bd4d 100644 --- a/Userland/Shell/Shell.cpp +++ b/Userland/Shell/Shell.cpp @@ -844,6 +844,14 @@ ErrorOr> Shell::run_command(const AST::Command& command) void Shell::execute_process(Vector&& argv) { +#ifdef __serenity__ + for (auto& promise : m_active_promises) { + pledge("exec", promise.data.exec_promises.characters()); + for (auto& item : promise.data.unveils) + unveil(item.path.characters(), item.access.characters()); + } +#endif + int rc = execvp(argv[0], const_cast(argv.data())); if (rc < 0) { auto parts = StringView { argv[0] }.split_view('/'); @@ -1833,6 +1841,13 @@ ErrorOr> Shell::complete_via_program_itself(s }); timer->start(); + // Restrict the process to effectively readonly access to the FS. + auto scoped_promise = promise({ + .exec_promises = "stdio rpath prot_exec no_error", + .unveils = { + { "/", "rx" }, + }, + }); execute_node->for_each_entry(*this, [&](NonnullRefPtr entry) -> IterationDecision { auto result = entry->resolve_as_string(*this); JsonParser parser(result); diff --git a/Userland/Shell/Shell.h b/Userland/Shell/Shell.h index e60a0cf155..6c1ac34c2d 100644 --- a/Userland/Shell/Shell.h +++ b/Userland/Shell/Shell.h @@ -159,6 +159,41 @@ public: [[nodiscard]] Frame push_frame(String name); void pop_frame(); + struct Promise { + struct Data { + struct Unveil { + String path; + String access; + }; + String exec_promises; + Vector unveils; + } data; + + IntrusiveListNode node; + using List = IntrusiveList<&Promise::node>; + }; + + struct ScopedPromise { + ScopedPromise(Promise::List& promises, Promise&& promise) + : promises(promises) + , promise(move(promise)) + { + promises.append(this->promise); + } + + ~ScopedPromise() + { + promises.remove(promise); + } + + Promise::List& promises; + Promise promise; + }; + [[nodiscard]] ScopedPromise promise(Promise::Data data) + { + return { m_active_promises, { move(data), {} } }; + } + enum class EscapeMode { Bareword, SingleQuotedString, @@ -362,6 +397,7 @@ private: HashMap m_functions; NonnullOwnPtrVector m_local_frames; + Promise::List m_active_promises; NonnullRefPtrVector m_global_redirections; HashMap m_aliases;