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

Commit 5123a3ea authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "ueventd: Run external handler as non-root group"

parents a6c57d57 10c6374e
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -123,7 +123,10 @@ not present.
The exact firmware file to be served can be customized by running an external program by a
`external_firmware_handler` line in a ueventd.rc file. This line takes the format of

    external_firmware_handler <devpath> <user name to run as> <path to external program>
    external_firmware_handler <devpath> <user [group]> <path to external program>

The handler will be run as the given user, or if a group is provided, as the given user and group.

For example

    external_firmware_handler /devices/leds/red/firmware/coeffs.bin system /vendor/bin/led_coeffs.bin
+17 −5
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <glob.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
@@ -81,9 +82,9 @@ static bool IsBooting() {
    return access("/dev/.booting", F_OK) == 0;
}

ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid,
                                                 std::string handler_path)
    : devpath(std::move(devpath)), uid(uid), handler_path(std::move(handler_path)) {
    : devpath(std::move(devpath)), uid(uid), gid(gid), handler_path(std::move(handler_path)) {
    auto wildcard_position = this->devpath.find('*');
    if (wildcard_position != std::string::npos) {
        if (wildcard_position == this->devpath.length() - 1) {
@@ -97,13 +98,17 @@ ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
    }
}

ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
                                                 std::string handler_path)
    : ExternalFirmwareHandler(devpath, uid, 0, handler_path) {}

FirmwareHandler::FirmwareHandler(std::vector<std::string> firmware_directories,
                                 std::vector<ExternalFirmwareHandler> external_firmware_handlers)
    : firmware_directories_(std::move(firmware_directories)),
      external_firmware_handlers_(std::move(external_firmware_handlers)) {}

Result<std::string> FirmwareHandler::RunExternalHandler(const std::string& handler, uid_t uid,
                                                        const Uevent& uevent) const {
                                                        gid_t gid, const Uevent& uevent) const {
    unique_fd child_stdout;
    unique_fd parent_stdout;
    if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stdout, &parent_stdout)) {
@@ -140,6 +145,13 @@ Result<std::string> FirmwareHandler::RunExternalHandler(const std::string& handl
        }
        c_args.emplace_back(nullptr);

        if (gid != 0) {
            if (setgid(gid) != 0) {
                fprintf(stderr, "setgid() failed: %s", strerror(errno));
                _exit(EXIT_FAILURE);
            }
        }

        if (setuid(uid) != 0) {
            fprintf(stderr, "setuid() failed: %s", strerror(errno));
            _exit(EXIT_FAILURE);
@@ -196,8 +208,8 @@ std::string FirmwareHandler::GetFirmwarePath(const Uevent& uevent) const {
                      << "' for devpath: '" << uevent.path << "' firmware: '" << uevent.firmware
                      << "'";

            auto result =
                    RunExternalHandler(external_handler.handler_path, external_handler.uid, uevent);
            auto result = RunExternalHandler(external_handler.handler_path, external_handler.uid,
                                             external_handler.gid, uevent);
            if (!result.ok()) {
                LOG(ERROR) << "Using default firmware; External firmware handler failed: "
                           << result.error();
+4 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <grp.h>
#include <pwd.h>

#include <functional>
@@ -31,9 +32,11 @@ namespace init {

struct ExternalFirmwareHandler {
    ExternalFirmwareHandler(std::string devpath, uid_t uid, std::string handler_path);
    ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid, std::string handler_path);

    std::string devpath;
    uid_t uid;
    gid_t gid;
    std::string handler_path;

    std::function<bool(const std::string&)> match;
@@ -51,7 +54,7 @@ class FirmwareHandler : public UeventHandler {
    friend void FirmwareTestWithExternalHandler(const std::string& test_name,
                                                bool expect_new_firmware);

    Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid,
    Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid, gid_t gid,
                                           const Uevent& uevent) const;
    std::string GetFirmwarePath(const Uevent& uevent) const;
    void ProcessFirmwareEvent(const std::string& root, const std::string& firmware) const;
+15 −3
Original line number Diff line number Diff line
@@ -101,8 +101,8 @@ Result<void> ParseFirmwareDirectoriesLine(std::vector<std::string>&& args,
Result<void> ParseExternalFirmwareHandlerLine(
        std::vector<std::string>&& args,
        std::vector<ExternalFirmwareHandler>* external_firmware_handlers) {
    if (args.size() != 4) {
        return Error() << "external_firmware_handler lines must have exactly 3 parameters";
    if (args.size() != 4 && args.size() != 5) {
        return Error() << "external_firmware_handler lines must have 3 or 4 parameters";
    }

    if (std::find_if(external_firmware_handlers->begin(), external_firmware_handlers->end(),
@@ -117,7 +117,19 @@ Result<void> ParseExternalFirmwareHandlerLine(
        return ErrnoError() << "invalid handler uid'" << args[2] << "'";
    }

    ExternalFirmwareHandler handler(std::move(args[1]), pwd->pw_uid, std::move(args[3]));
    gid_t gid = 0;
    int handler_index = 3;
    if (args.size() == 5) {
        struct group* grp = getgrnam(args[3].c_str());
        if (!grp) {
            return ErrnoError() << "invalid handler gid '" << args[3] << "'";
        }
        gid = grp->gr_gid;
        handler_index = 4;
    }

    ExternalFirmwareHandler handler(std::move(args[1]), pwd->pw_uid, gid,
                                    std::move(args[handler_index]));
    external_firmware_handlers->emplace_back(std::move(handler));

    return {};
+23 −1
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ void TestExternalFirmwareHandler(const ExternalFirmwareHandler& expected,
                                 const ExternalFirmwareHandler& test) {
    EXPECT_EQ(expected.devpath, test.devpath) << expected.devpath;
    EXPECT_EQ(expected.uid, test.uid) << expected.uid;
    EXPECT_EQ(expected.gid, test.gid) << expected.gid;
    EXPECT_EQ(expected.handler_path, test.handler_path) << expected.handler_path;
}

@@ -157,39 +158,59 @@ external_firmware_handler /devices/path/firmware/something002.bin radio "/vendor
external_firmware_handler /devices/path/firmware/* root "/vendor/bin/firmware_handler.sh"
external_firmware_handler /devices/path/firmware/something* system "/vendor/bin/firmware_handler.sh"
external_firmware_handler /devices/path/*/firmware/something*.bin radio "/vendor/bin/firmware_handler.sh"
external_firmware_handler /devices/path/firmware/something003.bin system system /vendor/bin/firmware_handler.sh
external_firmware_handler /devices/path/firmware/something004.bin radio radio "/vendor/bin/firmware_handler.sh --has --arguments"
)";

    auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
            {
                    "devpath",
                    AID_ROOT,
                    AID_ROOT,
                    "handler_path",
            },
            {
                    "/devices/path/firmware/something001.bin",
                    AID_SYSTEM,
                    AID_ROOT,
                    "/vendor/bin/firmware_handler.sh",
            },
            {
                    "/devices/path/firmware/something002.bin",
                    AID_RADIO,
                    AID_ROOT,
                    "/vendor/bin/firmware_handler.sh --has --arguments",
            },
            {
                    "/devices/path/firmware/",
                    AID_ROOT,
                    AID_ROOT,
                    "/vendor/bin/firmware_handler.sh",
            },
            {
                    "/devices/path/firmware/something",
                    AID_SYSTEM,
                    AID_ROOT,
                    "/vendor/bin/firmware_handler.sh",
            },
            {
                    "/devices/path/*/firmware/something*.bin",
                    AID_RADIO,
                    AID_ROOT,
                    "/vendor/bin/firmware_handler.sh",
            },
            {
                    "/devices/path/firmware/something003.bin",
                    AID_SYSTEM,
                    AID_SYSTEM,
                    "/vendor/bin/firmware_handler.sh",
            },
            {
                    "/devices/path/firmware/something004.bin",
                    AID_RADIO,
                    AID_RADIO,
                    "/vendor/bin/firmware_handler.sh --has --arguments",
            },
    };

    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
@@ -205,6 +226,7 @@ external_firmware_handler devpath root handler_path2
            {
                    "devpath",
                    AID_ROOT,
                    AID_ROOT,
                    "handler_path",
            },
    };
@@ -305,7 +327,7 @@ parallel_restorecon enabled
    };

    auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
            {"/devices/path/firmware/firmware001.bin", AID_ROOT, "/vendor/bin/touch.sh"},
            {"/devices/path/firmware/firmware001.bin", AID_ROOT, AID_ROOT, "/vendor/bin/touch.sh"},
    };

    size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024;