Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb0f9bbc authored by Tom Cherry's avatar Tom Cherry
Browse files

init: run vendor commands in a separate SELinux context

One of the major aspects of treble is the compartmentalization of system
and vendor components, however init leaves a huge gap here, as vendor
init scripts run in the same context as system init scripts and thus can
access and modify the same properties, files, etc as the system can.

This change is meant to close that gap.  It forks a separate 'subcontext'
init that runs in a different SELinux context with permissions that match
what vendors should have access to.  Commands get sent over a socket to
this 'subcontext' init that then runs them in this SELinux context and
returns the result.

Note that not all commands run in the subcontext; some commands such as
those dealing with services only make sense in the context of the main
init process.

Bug: 62875318
Test: init unit tests, boot bullhead, boot sailfish

Change-Id: Idf4a4ebf98842d27b8627f901f961ab9eb412aee
parent 9c568d0f
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -78,6 +78,8 @@ cc_library_static {
        "security.cpp",
        "selinux.cpp",
        "service.cpp",
        "subcontext.cpp",
        "subcontext.proto",
        "rlimit_parser.cpp",
        "tokenizer.cpp",
        "uevent_listener.cpp",
@@ -173,6 +175,7 @@ cc_test {
        "result_test.cpp",
        "rlimit_parser_test.cpp",
        "service_test.cpp",
        "subcontext_test.cpp",
        "ueventd_test.cpp",
        "util_test.cpp",
    ],
@@ -188,4 +191,22 @@ cc_test {
    ],
}

cc_benchmark {
    name: "init_benchmarks",
    defaults: ["init_defaults"],
    srcs: [
        "subcontext_benchmark.cpp",
    ],
    shared_libs: [
        "libbase",
        "libcutils",
    ],
    static_libs: [
        "libinit",
        "libselinux",
        "libcrypto",
        "libprotobuf-cpp-lite",
    ],
}

subdirs = ["*"]
+42 −18
Original line number Diff line number Diff line
@@ -24,34 +24,48 @@
#include "util.h"

using android::base::Join;
using android::base::StartsWith;

namespace android {
namespace init {

Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line)
    : func_(f), args_(args), line_(line) {}
Result<Success> RunBuiltinFunction(const BuiltinFunction& function,
                                   const std::vector<std::string>& args,
                                   const std::string& context) {
    auto builtin_arguments = BuiltinArguments(context);

Result<Success> Command::InvokeFunc() const {
    std::vector<std::string> expanded_args;
    expanded_args.resize(args_.size());
    expanded_args[0] = args_[0];
    for (std::size_t i = 1; i < args_.size(); ++i) {
        if (!expand_props(args_[i], &expanded_args[i])) {
            return Error() << "cannot expand '" << args_[i] << "'";
    builtin_arguments.args.resize(args.size());
    builtin_arguments.args[0] = args[0];
    for (std::size_t i = 1; i < args.size(); ++i) {
        if (!expand_props(args[i], &builtin_arguments.args[i])) {
            return Error() << "cannot expand '" << args[i] << "'";
        }
    }

    return func_(expanded_args);
    return function(builtin_arguments);
}

Command::Command(BuiltinFunction f, bool execute_in_subcontext,
                 const std::vector<std::string>& args, int line)
    : func_(std::move(f)), execute_in_subcontext_(execute_in_subcontext), args_(args), line_(line) {}

Result<Success> Command::InvokeFunc(Subcontext* subcontext) const {
    if (execute_in_subcontext_ && subcontext) {
        return subcontext->Execute(args_);
    } else {
        const std::string& context = subcontext ? subcontext->context() : kInitContext;
        return RunBuiltinFunction(func_, args_, context);
    }
}

std::string Command::BuildCommandString() const {
    return Join(args_, ' ');
}

Action::Action(bool oneshot, const std::string& filename, int line)
    : oneshot_(oneshot), filename_(filename), line_(line) {}
Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line)
    : oneshot_(oneshot), subcontext_(subcontext), filename_(filename), line_(line) {}

const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr;
const KeywordFunctionMap* Action::function_map_ = nullptr;

Result<Success> Action::AddCommand(const std::vector<std::string>& args, int line) {
    if (!function_map_) {
@@ -61,12 +75,12 @@ Result<Success> Action::AddCommand(const std::vector<std::string>& args, int lin
    auto function = function_map_->FindFunction(args);
    if (!function) return Error() << function.error();

    AddCommand(*function, args, line);
    commands_.emplace_back(function->second, function->first, args, line);
    return Success();
}

void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) {
    commands_.emplace_back(f, args, line);
    commands_.emplace_back(f, false, args, line);
}

std::size_t Action::NumCommands() const {
@@ -88,7 +102,7 @@ void Action::ExecuteAllCommands() const {

void Action::ExecuteCommand(const Command& command) const {
    android::base::Timer t;
    auto result = command.InvokeFunc();
    auto result = command.InvokeFunc(subcontext_);
    auto duration = t.duration();

    // There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
@@ -261,7 +275,7 @@ void ActionManager::QueueAllPropertyActions() {
}

void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
    auto action = std::make_unique<Action>(true, "<Builtin Action>", 0);
    auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0);
    std::vector<std::string> name_vector{name};

    if (auto result = action->InitSingleTrigger(name); !result) {
@@ -341,7 +355,17 @@ Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
        return Error() << "Actions must have a trigger";
    }

    auto action = std::make_unique<Action>(false, filename, line);
    Subcontext* action_subcontext = nullptr;
    if (subcontexts_) {
        for (auto& subcontext : *subcontexts_) {
            if (StartsWith(filename, subcontext.path_prefix().c_str())) {
                action_subcontext = &subcontext;
                break;
            }
        }
    }

    auto action = std::make_unique<Action>(false, action_subcontext, filename, line);

    if (auto result = action->InitTriggers(triggers); !result) {
        return Error() << "InitTriggers() failed: " << result.error();
+16 −9
Original line number Diff line number Diff line
@@ -27,21 +27,27 @@
#include "keyword_map.h"
#include "parser.h"
#include "result.h"
#include "subcontext.h"

namespace android {
namespace init {

Result<Success> RunBuiltinFunction(const BuiltinFunction& function,
                                   const std::vector<std::string>& args, const std::string& context);

class Command {
  public:
    Command(BuiltinFunction f, const std::vector<std::string>& args, int line);
    Command(BuiltinFunction f, bool execute_in_subcontext, const std::vector<std::string>& args,
            int line);

    Result<Success> InvokeFunc() const;
    Result<Success> InvokeFunc(Subcontext* subcontext) const;
    std::string BuildCommandString() const;

    int line() const { return line_; }

  private:
    BuiltinFunction func_;
    bool execute_in_subcontext_;
    std::vector<std::string> args_;
    int line_;
};
@@ -52,7 +58,7 @@ using BuiltinAction = class Action*;

class Action {
  public:
    explicit Action(bool oneshot, const std::string& filename, int line);
    Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line);

    Result<Success> AddCommand(const std::vector<std::string>& args, int line);
    void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line);
@@ -70,11 +76,10 @@ class Action {
    bool oneshot() const { return oneshot_; }
    const std::string& filename() const { return filename_; }
    int line() const { return line_; }
    static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) {
    static void set_function_map(const KeywordFunctionMap* function_map) {
        function_map_ = function_map;
    }


  private:
    void ExecuteCommand(const Command& command) const;
    bool CheckPropertyTriggers(const std::string& name = "",
@@ -85,9 +90,10 @@ private:
    std::string event_trigger_;
    std::vector<Command> commands_;
    bool oneshot_;
    Subcontext* subcontext_;
    std::string filename_;
    int line_;
    static const KeywordMap<BuiltinFunction>* function_map_;
    static const KeywordFunctionMap* function_map_;
};

class ActionManager {
@@ -119,8 +125,8 @@ class ActionManager {

class ActionParser : public SectionParser {
  public:
    ActionParser(ActionManager* action_manager)
        : action_manager_(action_manager), action_(nullptr) {}
    ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts)
        : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {}
    Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
                                 int line) override;
    Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
@@ -128,6 +134,7 @@ class ActionParser : public SectionParser {

  private:
    ActionManager* action_manager_;
    std::vector<Subcontext>* subcontexts_;
    std::unique_ptr<Action> action_;
};

+1 −1
Original line number Diff line number Diff line
@@ -191,7 +191,7 @@ static Result<Success> do_bootchart_stop() {
    return Success();
}

Result<Success> do_bootchart(const std::vector<std::string>& args) {
Result<Success> do_bootchart(const BuiltinArguments& args) {
    if (args[1] == "start") return do_bootchart_start();
    return do_bootchart_stop();
}
+2 −1
Original line number Diff line number Diff line
@@ -20,12 +20,13 @@
#include <string>
#include <vector>

#include "builtin_arguments.h"
#include "result.h"

namespace android {
namespace init {

Result<Success> do_bootchart(const std::vector<std::string>& args);
Result<Success> do_bootchart(const BuiltinArguments& args);

}  // namespace init
}  // namespace android
Loading