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

Commit a8992075 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 4799153 from 428a6ffa to pi-release

Change-Id: I8b50c825ba0cdcaedd4729b759cecf5ee3d48a4c
parents f2ca6c24 428a6ffa
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -187,6 +187,10 @@ runs the service.
  seclabel or computed based on the service executable file security context.
  For native executables see libcutils android\_get\_control\_socket().

`enter_namespace <type> <path>`
> Enters the namespace of type _type_ located at _path_. Only network namespaces are supported with
  _type_ set to "net". Note that only one namespace of a given _type_ may be entered.

`file <path> <type>`
> Open a file path and pass its fd to the launched process. _type_ must be
  "r", "w" or "rw".  For native executables see libcutils
+39 −11
Original line number Diff line number Diff line
@@ -95,6 +95,11 @@ uint32_t (*property_set)(const std::string& name, const std::string& value) = In

void CreateSerializedPropertyInfo();

struct PropertyAuditData {
    const ucred* cr;
    const char* name;
};

void property_init() {
    mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
    CreateSerializedPropertyInfo();
@@ -111,7 +116,7 @@ static bool CheckMacPerms(const std::string& name, const char* target_context,
        return false;
    }

    property_audit_data audit_data;
    PropertyAuditData audit_data;

    audit_data.name = name.c_str();
    audit_data.cr = &cr;
@@ -388,6 +393,35 @@ class SocketConnection {
    DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
};

bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
                               const std::string& source_context, const ucred& cr) {
    // We check the legacy method first but these properties are dontaudit, so we only log an audit
    // if the newer method fails as well.  We only do this with the legacy ctl. properties.
    if (name == "ctl.start" || name == "ctl.stop" || name == "ctl.restart") {
        // The legacy permissions model is that ctl. properties have their name ctl.<action> and
        // their value is the name of the service to apply that action to.  Permissions for these
        // actions are based on the service, so we must create a fake name of ctl.<service> to
        // check permissions.
        auto control_string_legacy = "ctl." + value;
        const char* target_context_legacy = nullptr;
        const char* type_legacy = nullptr;
        property_info_area->GetPropertyInfo(control_string_legacy.c_str(), &target_context_legacy,
                                            &type_legacy);

        if (CheckMacPerms(control_string_legacy, target_context_legacy, source_context.c_str(), cr)) {
            return true;
        }
    }

    auto control_string_full = name + "$" + value;
    const char* target_context_full = nullptr;
    const char* type_full = nullptr;
    property_info_area->GetPropertyInfo(control_string_full.c_str(), &target_context_full,
                                        &type_full);

    return CheckMacPerms(control_string_full, target_context_full, source_context.c_str(), cr);
}

// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                           const std::string& source_context, const ucred& cr, std::string* error) {
@@ -397,15 +431,9 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
    }

    if (StartsWith(name, "ctl.")) {
        // ctl. properties have their name ctl.<action> and their value is the name of the service
        // to apply that action to.  Permissions for these actions are based on the service, so we
        // must create a fake name of ctl.<service> to check permissions.
        auto control_string = "ctl." + value;
        const char* target_context = nullptr;
        const char* type = nullptr;
        property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
        if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) {
            *error = StringPrintf("Unable to '%s' service %s", name.c_str() + 4, value.c_str());
        if (!CheckControlPropertyPerms(name, value, source_context, cr)) {
            *error = StringPrintf("Invalid permissions to perform '%s' on '%s'", name.c_str() + 4,
                                  value.c_str());
            return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
        }

@@ -737,7 +765,7 @@ void load_system_props() {
}

static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
    property_audit_data* d = reinterpret_cast<property_audit_data*>(data);
    auto* d = reinterpret_cast<PropertyAuditData*>(data);

    if (!d || !d->name || !d->cr) {
        LOG(ERROR) << "AuditCallback invoked with null data arguments!";
+0 −5
Original line number Diff line number Diff line
@@ -24,11 +24,6 @@
namespace android {
namespace init {

struct property_audit_data {
    const ucred* cr;
    const char* name;
};

extern uint32_t (*property_set)(const std::string& name, const std::string& value);

uint32_t HandlePropertySet(const std::string& name, const std::string& value,
+75 −17
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <hidl-util/FQName.h>
#include <processgroup/processgroup.h>
#include <selinux/selinux.h>
@@ -59,13 +60,13 @@ using android::base::Join;
using android::base::ParseInt;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::unique_fd;
using android::base::WriteStringToFile;

namespace android {
namespace init {

static Result<std::string> ComputeContextFromExecutable(std::string& service_name,
                                                        const std::string& service_path) {
static Result<std::string> ComputeContextFromExecutable(const std::string& service_path) {
    std::string computed_context;

    char* raw_con = nullptr;
@@ -101,36 +102,49 @@ static Result<std::string> ComputeContextFromExecutable(std::string& service_nam
    return computed_context;
}

static void SetUpPidNamespace(const std::string& service_name) {
Result<Success> Service::SetUpMountNamespace() const {
    constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;

    // It's OK to LOG(FATAL) in this function since it's running in the first
    // child process.

    // Recursively remount / as slave like zygote does so unmounting and mounting /proc
    // doesn't interfere with the parent namespace's /proc mount. This will also
    // prevent any other mounts/unmounts initiated by the service from interfering
    // with the parent namespace but will still allow mount events from the parent
    // namespace to propagate to the child.
    if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
        PLOG(FATAL) << "couldn't remount(/) recursively as slave for " << service_name;
        return ErrnoError() << "Could not remount(/) recursively as slave";
    }
    // umount() then mount() /proc.

    // umount() then mount() /proc and/or /sys
    // Note that it is not sufficient to mount with MS_REMOUNT.
    if (namespace_flags_ & CLONE_NEWPID) {
        if (umount("/proc") == -1) {
        PLOG(FATAL) << "couldn't umount(/proc) for " << service_name;
            return ErrnoError() << "Could not umount(/proc)";
        }
        if (mount("", "/proc", "proc", kSafeFlags, "") == -1) {
        PLOG(FATAL) << "couldn't mount(/proc) for " << service_name;
            return ErrnoError() << "Could not mount(/proc)";
        }
    }
    bool remount_sys = std::any_of(namespaces_to_enter_.begin(), namespaces_to_enter_.end(),
                                   [](const auto& entry) { return entry.first == CLONE_NEWNET; });
    if (remount_sys) {
        if (umount2("/sys", MNT_DETACH) == -1) {
            return ErrnoError() << "Could not umount(/sys)";
        }
        if (mount("", "/sys", "sys", kSafeFlags, "") == -1) {
            return ErrnoError() << "Could not mount(/sys)";
        }
    }
    return Success();
}

    if (prctl(PR_SET_NAME, service_name.c_str()) == -1) {
        PLOG(FATAL) << "couldn't set name for " << service_name;
Result<Success> Service::SetUpPidNamespace() const {
    if (prctl(PR_SET_NAME, name_.c_str()) == -1) {
        return ErrnoError() << "Could not set name";
    }

    pid_t child_pid = fork();
    if (child_pid == -1) {
        PLOG(FATAL) << "couldn't fork init inside the PID namespace for " << service_name;
        return ErrnoError() << "Could not fork init inside the PID namespace";
    }

    if (child_pid > 0) {
@@ -153,6 +167,20 @@ static void SetUpPidNamespace(const std::string& service_name) {
        }
        _exit(WEXITSTATUS(init_exitstatus));
    }
    return Success();
}

Result<Success> Service::EnterNamespaces() const {
    for (const auto& [nstype, path] : namespaces_to_enter_) {
        auto fd = unique_fd{open(path.c_str(), O_RDONLY | O_CLOEXEC)};
        if (!fd) {
            return ErrnoError() << "Could not open namespace at " << path;
        }
        if (setns(fd, nstype) == -1) {
            return ErrnoError() << "Could not setns() namespace at " << path;
        }
    }
    return Success();
}

static bool ExpandArgsAndExecv(const std::vector<std::string>& args) {
@@ -418,6 +446,20 @@ Result<Success> Service::ParseDisabled(const std::vector<std::string>& args) {
    return Success();
}

Result<Success> Service::ParseEnterNamespace(const std::vector<std::string>& args) {
    if (args[1] != "net") {
        return Error() << "Init only supports entering network namespaces";
    }
    if (!namespaces_to_enter_.empty()) {
        return Error() << "Only one network namespace may be entered";
    }
    // Network namespaces require that /sys is remounted, otherwise the old adapters will still be
    // present. Therefore, they also require mount namespaces.
    namespace_flags_ |= CLONE_NEWNS;
    namespaces_to_enter_.emplace_back(CLONE_NEWNET, args[2]);
    return Success();
}

Result<Success> Service::ParseGroup(const std::vector<std::string>& args) {
    auto gid = DecodeUid(args[1]);
    if (!gid) {
@@ -682,6 +724,8 @@ const Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
        {"console",     {0,     1,    &Service::ParseConsole}},
        {"critical",    {0,     0,    &Service::ParseCritical}},
        {"disabled",    {0,     0,    &Service::ParseDisabled}},
        {"enter_namespace",
                        {2,     2,    &Service::ParseEnterNamespace}},
        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
        {"interface",   {2,     2,    &Service::ParseInterface}},
        {"ioprio",      {2,     2,    &Service::ParseIoprio}},
@@ -783,7 +827,7 @@ Result<Success> Service::Start() {
    if (!seclabel_.empty()) {
        scon = seclabel_;
    } else {
        auto result = ComputeContextFromExecutable(name_, args_[0]);
        auto result = ComputeContextFromExecutable(args_[0]);
        if (!result) {
            return result.error();
        }
@@ -802,10 +846,24 @@ Result<Success> Service::Start() {
    if (pid == 0) {
        umask(077);

        if (auto result = EnterNamespaces(); !result) {
            LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error();
        }

        if (namespace_flags_ & CLONE_NEWNS) {
            if (auto result = SetUpMountNamespace(); !result) {
                LOG(FATAL) << "Service '" << name_
                           << "' could not set up mount namespace: " << result.error();
            }
        }

        if (namespace_flags_ & CLONE_NEWPID) {
            // This will fork again to run an init process inside the PID
            // namespace.
            SetUpPidNamespace(name_);
            if (auto result = SetUpPidNamespace(); !result) {
                LOG(FATAL) << "Service '" << name_
                           << "' could not set up PID namespace: " << result.error();
            }
        }

        for (const auto& [key, value] : environment_vars_) {
+6 −0
Original line number Diff line number Diff line
@@ -124,6 +124,9 @@ class Service {
    using OptionParser = Result<Success> (Service::*)(const std::vector<std::string>& args);
    class OptionParserMap;

    Result<Success> SetUpMountNamespace() const;
    Result<Success> SetUpPidNamespace() const;
    Result<Success> EnterNamespaces() const;
    void NotifyStateChange(const std::string& new_state) const;
    void StopOrReset(int how);
    void ZapStdio() const;
@@ -136,6 +139,7 @@ class Service {
    Result<Success> ParseConsole(const std::vector<std::string>& args);
    Result<Success> ParseCritical(const std::vector<std::string>& args);
    Result<Success> ParseDisabled(const std::vector<std::string>& args);
    Result<Success> ParseEnterNamespace(const std::vector<std::string>& args);
    Result<Success> ParseGroup(const std::vector<std::string>& args);
    Result<Success> ParsePriority(const std::vector<std::string>& args);
    Result<Success> ParseInterface(const std::vector<std::string>& args);
@@ -179,6 +183,8 @@ class Service {
    std::vector<gid_t> supp_gids_;
    CapSet capabilities_;
    unsigned namespace_flags_;
    // Pair of namespace type, path to namespace.
    std::vector<std::pair<int, std::string>> namespaces_to_enter_;

    std::string seclabel_;

Loading