Browse Source

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.
Ali Mohammad Pur 3 năm trước cách đây
mục cha
commit
f12d81ddf5
2 tập tin đã thay đổi với 51 bổ sung0 xóa
  1. 15 0
      Userland/Shell/Shell.cpp
  2. 36 0
      Userland/Shell/Shell.h

+ 15 - 0
Userland/Shell/Shell.cpp

@@ -844,6 +844,14 @@ ErrorOr<RefPtr<Job>> Shell::run_command(const AST::Command& command)
 
 void Shell::execute_process(Vector<const char*>&& 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<char* const*>(argv.data()));
     if (rc < 0) {
         auto parts = StringView { argv[0] }.split_view('/');
@@ -1833,6 +1841,13 @@ ErrorOr<Vector<Line::CompletionSuggestion>> 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<AST::Value> entry) -> IterationDecision {
         auto result = entry->resolve_as_string(*this);
         JsonParser parser(result);

+ 36 - 0
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<Unveil> unveils;
+        } data;
+
+        IntrusiveListNode<Promise> 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<String, ShellFunction> m_functions;
     NonnullOwnPtrVector<LocalFrame> m_local_frames;
+    Promise::List m_active_promises;
     NonnullRefPtrVector<AST::Redirection> m_global_redirections;
 
     HashMap<String, String> m_aliases;