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

Commit f0bc58a4 authored by Martijn Coenen's avatar Martijn Coenen
Browse files

Support for stopping/starting post-data-mount class subsets.

On devices that use FDE and APEX at the same time, we need to bring up a
minimal framework to be able to mount the /data partition. During this
period, a tmpfs /data filesystem is created, which doesn't contain any
of the updated APEXEs. As a consequence, all those processes will be
using the APEXes from the /system partition.

This is obviously not desired, as APEXes in /system may be old and/or
contain security issues. Additionally, it would create a difference
between FBE and FDE devices at runtime.

Ideally, we restart all processes that have started after we created the
tmpfs /data. We can't (re)start based on class names alone, because some
classes (eg 'hal') contain services that are required to start apexd
itself and that shouldn't be killed (eg the graphics HAL).

To address this, keep track of which processes are started after /data
is mounted, with a new 'mark_post_data' keyword. Additionally, create
'class_reset_post_data', which resets all services in the class that
were created after the initial /data mount, and 'class_start_post_data',
which starts all services in the class that were started after /data was
mounted.

On a device with FBE, these keywords wouldn't be used; on a device with
FDE, we'd use them to bring down the right processes after the user has
entered the correct secret, and restart them.

Bug: 118485723
Test: manually verified process list
Change-Id: I16adb776dacf1dd1feeaff9e60639b99899905eb
parent a04e48db
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -412,6 +412,10 @@ Commands
  not already running.  See the start entry for more information on
  starting services.

`class_start_post_data <serviceclass>`
> Like `class_start`, but only considers services that were started
  after /data was mounted. Only used for FDE devices.

`class_stop <serviceclass>`
> Stop and disable all services of the specified class if they are
  currently running.
@@ -421,6 +425,10 @@ Commands
  currently running, without disabling them. They can be restarted
  later using `class_start`.

`class_reset_post_data <serviceclass>`
> Like `class_reset`, but only considers services that were started
  after /data was mounted. Only used for FDE devices.

`class_restart <serviceclass>`
> Restarts all services of the specified class.

@@ -490,6 +498,10 @@ Commands
`loglevel <level>`
> Sets the kernel log level to level. Properties are expanded within _level_.

`mark_post_data`
> Used to mark the point right after /data is mounted. Used to implement the
  `class_reset_post_data` and `class_start_post_data` commands.

`mkdir <path> [mode] [owner] [group]`
> Create a directory at _path_, optionally with the given mode, owner, and
  group. If not provided, the directory is created with permissions 755 and
+35 −4
Original line number Diff line number Diff line
@@ -104,23 +104,37 @@ static void ForEachServiceInClass(const std::string& classname, F function) {
    }
}

static Result<Success> do_class_start(const BuiltinArguments& args) {
static Result<Success> class_start(const std::string& class_name, bool post_data_only) {
    // Do not start a class if it has a property persist.dont_start_class.CLASS set to 1.
    if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
    if (android::base::GetBoolProperty("persist.init.dont_start_class." + class_name, false))
        return Success();
    // Starting a class does not start services which are explicitly disabled.
    // They must  be started individually.
    for (const auto& service : ServiceList::GetInstance()) {
        if (service->classnames().count(args[1])) {
        if (service->classnames().count(class_name)) {
            if (post_data_only && !service->is_post_data()) {
                continue;
            }
            if (auto result = service->StartIfNotDisabled(); !result) {
                LOG(ERROR) << "Could not start service '" << service->name()
                           << "' as part of class '" << args[1] << "': " << result.error();
                           << "' as part of class '" << class_name << "': " << result.error();
            }
        }
    }
    return Success();
}

static Result<Success> do_class_start(const BuiltinArguments& args) {
    return class_start(args[1], false /* post_data_only */);
}

static Result<Success> do_class_start_post_data(const BuiltinArguments& args) {
    if (args.context != kInitContext) {
        return Error() << "command 'class_start_post_data' only available in init context";
    }
    return class_start(args[1], true /* post_data_only */);
}

static Result<Success> do_class_stop(const BuiltinArguments& args) {
    ForEachServiceInClass(args[1], &Service::Stop);
    return Success();
@@ -131,6 +145,14 @@ static Result<Success> do_class_reset(const BuiltinArguments& args) {
    return Success();
}

static Result<Success> do_class_reset_post_data(const BuiltinArguments& args) {
    if (args.context != kInitContext) {
        return Error() << "command 'class_reset_post_data' only available in init context";
    }
    ForEachServiceInClass(args[1], &Service::ResetIfPostData);
    return Success();
}

static Result<Success> do_class_restart(const BuiltinArguments& args) {
    // Do not restart a class if it has a property persist.dont_start_class.CLASS set to 1.
    if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
@@ -1119,6 +1141,12 @@ static Result<Success> do_init_user0(const BuiltinArguments& args) {
        {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
}

static Result<Success> do_mark_post_data(const BuiltinArguments& args) {
    ServiceList::GetInstance().MarkPostData();

    return Success();
}

static Result<Success> do_parse_apex_configs(const BuiltinArguments& args) {
    glob_t glob_result;
    // @ is added to filter out the later paths, which are bind mounts of the places
@@ -1170,8 +1198,10 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
        {"chmod",                   {2,     2,    {true,   do_chmod}}},
        {"chown",                   {2,     3,    {true,   do_chown}}},
        {"class_reset",             {1,     1,    {false,  do_class_reset}}},
        {"class_reset_post_data",   {1,     1,    {false,  do_class_reset_post_data}}},
        {"class_restart",           {1,     1,    {false,  do_class_restart}}},
        {"class_start",             {1,     1,    {false,  do_class_start}}},
        {"class_start_post_data",   {1,     1,    {false,  do_class_start_post_data}}},
        {"class_stop",              {1,     1,    {false,  do_class_stop}}},
        {"copy",                    {2,     2,    {true,   do_copy}}},
        {"domainname",              {1,     1,    {true,   do_domainname}}},
@@ -1191,6 +1221,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
        {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
        {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
        {"loglevel",                {1,     1,    {false,  do_loglevel}}},
        {"mark_post_data",          {0,     0,    {false,  do_mark_post_data}}},
        {"mkdir",                   {1,     4,    {true,   do_mkdir}}},
        // TODO: Do mount operations in vendor_init.
        // mount_all is currently too complex to run in vendor_init as it queues action triggers,
+17 −1
Original line number Diff line number Diff line
@@ -362,7 +362,7 @@ void Service::Reap(const siginfo_t& siginfo) {

    // Oneshot processes go into the disabled state on exit,
    // except when manually restarted.
    if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART)) {
    if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART) && !(flags_ & SVC_RESET)) {
        flags_ |= SVC_DISABLED;
    }

@@ -947,6 +947,8 @@ Result<Success> Service::Start() {
        pre_apexd_ = true;
    }

    post_data_ = ServiceList::GetInstance().IsPostData();

    LOG(INFO) << "starting service '" << name_ << "'...";

    pid_t pid = -1;
@@ -1146,6 +1148,12 @@ void Service::Reset() {
    StopOrReset(SVC_RESET);
}

void Service::ResetIfPostData() {
    if (post_data_) {
        StopOrReset(SVC_RESET);
    }
}

void Service::Stop() {
    StopOrReset(SVC_DISABLED);
}
@@ -1339,6 +1347,14 @@ void ServiceList::DumpState() const {
    }
}

void ServiceList::MarkPostData() {
    post_data_ = true;
}

bool ServiceList::IsPostData() {
    return post_data_;
}

void ServiceList::MarkServicesUpdate() {
    services_update_finished_ = true;

+7 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ class Service {
    Result<Success> StartIfNotDisabled();
    Result<Success> Enable();
    void Reset();
    void ResetIfPostData();
    void Stop();
    void Terminate();
    void Timeout();
@@ -124,6 +125,7 @@ class Service {
    std::optional<std::chrono::seconds> timeout_period() const { return timeout_period_; }
    const std::vector<std::string>& args() const { return args_; }
    bool is_updatable() const { return updatable_; }
    bool is_post_data() const { return post_data_; }

  private:
    using OptionParser = Result<Success> (Service::*)(std::vector<std::string>&& args);
@@ -244,6 +246,8 @@ class Service {
    std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;

    bool pre_apexd_ = false;

    bool post_data_ = false;
};

class ServiceList {
@@ -285,6 +289,8 @@ class ServiceList {
    const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
    const std::vector<Service*> services_in_shutdown_order() const;

    void MarkPostData();
    bool IsPostData();
    void MarkServicesUpdate();
    bool IsServicesUpdated() const { return services_update_finished_; }
    void DelayService(const Service& service);
@@ -292,6 +298,7 @@ class ServiceList {
  private:
    std::vector<std::unique_ptr<Service>> services_;

    bool post_data_ = false;
    bool services_update_finished_ = false;
    std::vector<std::string> delayed_service_names_;
};
+6 −3
Original line number Diff line number Diff line
@@ -405,6 +405,8 @@ on late-fs
    class_start early_hal

on post-fs-data
    mark_post_data

    # Start checkpoint before we touch data
    start vold
    exec - system system -- /system/bin/vdc checkpoint prepareCheckpoint
@@ -753,9 +755,6 @@ on property:sys.init_log_level=*
on charger
    class_start charger

on property:vold.decrypt=trigger_reset_main
    class_reset main

on property:vold.decrypt=trigger_load_persist_props
    load_persist_props
    start logd
@@ -773,6 +772,8 @@ on property:vold.decrypt=trigger_restart_min_framework
on property:vold.decrypt=trigger_restart_framework
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier
    class_start_post_data hal
    class_start_post_data core
    class_start main
    class_start late_start
    setprop service.bootanim.exit 0
@@ -781,6 +782,8 @@ on property:vold.decrypt=trigger_restart_framework
on property:vold.decrypt=trigger_shutdown_framework
    class_reset late_start
    class_reset main
    class_reset_post_data core
    class_reset_post_data hal

on property:sys.boot_completed=1
    bootchart stop