ueventd: require opt-in for modalias handling
Some devices have modules.alias and modules.dep for modprobe and other purposes but do not want to opt into ueventd auto loading their modules. Therefore we add a flag that can be added to ueventd configuration files to opt into this behavior. Bug: 111916071 Bug: 112048758 Test: check that modules are loaded with this opt-in Test: check that modules are not loaded without this opt-in Change-Id: Ifb281b273059b4671eea1ca5bc726c9e79f3adfb
This commit is contained in:
parent
081b710b2e
commit
457e28f129
11 changed files with 122 additions and 44 deletions
|
@ -372,7 +372,7 @@ void DeviceHandler::HandleDevice(const std::string& action, const std::string& d
|
|||
}
|
||||
}
|
||||
|
||||
void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
|
||||
void DeviceHandler::HandleUevent(const Uevent& uevent) {
|
||||
if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
|
||||
FixupSysPermissions(uevent.path, uevent.subsystem);
|
||||
}
|
||||
|
@ -418,6 +418,10 @@ void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
|
|||
HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
|
||||
}
|
||||
|
||||
void DeviceHandler::ColdbootDone() {
|
||||
skip_restorecon_ = true;
|
||||
}
|
||||
|
||||
DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
|
||||
std::vector<SysfsPermissions> sysfs_permissions,
|
||||
std::vector<Subsystem> subsystems, std::set<std::string> boot_devices,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <selinux/label.h>
|
||||
|
||||
#include "uevent.h"
|
||||
#include "uevent_handler.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
@ -105,7 +106,7 @@ class Subsystem {
|
|||
std::string dir_name_ = "/dev";
|
||||
};
|
||||
|
||||
class DeviceHandler {
|
||||
class DeviceHandler : public UeventHandler {
|
||||
public:
|
||||
friend class DeviceHandlerTester;
|
||||
|
||||
|
@ -113,11 +114,12 @@ class DeviceHandler {
|
|||
DeviceHandler(std::vector<Permissions> dev_permissions,
|
||||
std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> subsystems,
|
||||
std::set<std::string> boot_devices, bool skip_restorecon);
|
||||
virtual ~DeviceHandler() = default;
|
||||
|
||||
void HandleDeviceEvent(const Uevent& uevent);
|
||||
void HandleUevent(const Uevent& uevent) override;
|
||||
void ColdbootDone() override;
|
||||
|
||||
std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
|
||||
void set_skip_restorecon(bool value) { skip_restorecon_ = value; }
|
||||
|
||||
private:
|
||||
bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
|
||||
|
|
|
@ -35,8 +35,6 @@ using android::base::WriteFully;
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
std::vector<std::string> firmware_directories;
|
||||
|
||||
static void LoadFirmware(const Uevent& uevent, const std::string& root, int fw_fd, size_t fw_size,
|
||||
int loading_fd, int data_fd) {
|
||||
// Start transfer.
|
||||
|
@ -58,7 +56,10 @@ static bool IsBooting() {
|
|||
return access("/dev/.booting", F_OK) == 0;
|
||||
}
|
||||
|
||||
static void ProcessFirmwareEvent(const Uevent& uevent) {
|
||||
FirmwareHandler::FirmwareHandler(std::vector<std::string> firmware_directories)
|
||||
: firmware_directories_(std::move(firmware_directories)) {}
|
||||
|
||||
void FirmwareHandler::ProcessFirmwareEvent(const Uevent& uevent) {
|
||||
int booting = IsBooting();
|
||||
|
||||
LOG(INFO) << "firmware: loading '" << uevent.firmware << "' for '" << uevent.path << "'";
|
||||
|
@ -80,7 +81,7 @@ static void ProcessFirmwareEvent(const Uevent& uevent) {
|
|||
}
|
||||
|
||||
try_loading_again:
|
||||
for (const auto& firmware_directory : firmware_directories) {
|
||||
for (const auto& firmware_directory : firmware_directories_) {
|
||||
std::string file = firmware_directory + uevent.firmware;
|
||||
unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
|
||||
struct stat sb;
|
||||
|
@ -104,7 +105,7 @@ try_loading_again:
|
|||
write(loading_fd, "-1", 2);
|
||||
}
|
||||
|
||||
void HandleFirmwareEvent(const Uevent& uevent) {
|
||||
void FirmwareHandler::HandleUevent(const Uevent& uevent) {
|
||||
if (uevent.subsystem != "firmware" || uevent.action != "add") return;
|
||||
|
||||
// Loading the firmware in a child means we can do that in parallel...
|
||||
|
|
|
@ -21,13 +21,23 @@
|
|||
#include <vector>
|
||||
|
||||
#include "uevent.h"
|
||||
#include "uevent_handler.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
extern std::vector<std::string> firmware_directories;
|
||||
class FirmwareHandler : public UeventHandler {
|
||||
public:
|
||||
explicit FirmwareHandler(std::vector<std::string> firmware_directories);
|
||||
virtual ~FirmwareHandler() = default;
|
||||
|
||||
void HandleFirmwareEvent(const Uevent& uevent);
|
||||
void HandleUevent(const Uevent& uevent) override;
|
||||
|
||||
private:
|
||||
void ProcessFirmwareEvent(const Uevent& uevent);
|
||||
|
||||
std::vector<std::string> firmware_directories_;
|
||||
};
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
@ -206,7 +206,7 @@ bool FirstStageMount::InitRequiredDevices() {
|
|||
bool found = false;
|
||||
auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
|
||||
if (uevent.path == dm_path) {
|
||||
device_handler_->HandleDeviceEvent(uevent);
|
||||
device_handler_->HandleUevent(uevent);
|
||||
found = true;
|
||||
return ListenerAction::kStop;
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const
|
|||
lp_metadata_partition_ = links[0];
|
||||
}
|
||||
required_devices_partition_names_.erase(iter);
|
||||
device_handler_->HandleDeviceEvent(uevent);
|
||||
device_handler_->HandleUevent(uevent);
|
||||
if (required_devices_partition_names_.empty()) {
|
||||
return ListenerAction::kStop;
|
||||
} else {
|
||||
|
@ -310,7 +310,7 @@ bool FirstStageMount::InitMappedDevice(const std::string& dm_device) {
|
|||
auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) {
|
||||
if (uevent.device_name == device_name) {
|
||||
LOG(VERBOSE) << "Creating device-mapper device : " << dm_device;
|
||||
device_handler_->HandleDeviceEvent(uevent);
|
||||
device_handler_->HandleUevent(uevent);
|
||||
found = true;
|
||||
return ListenerAction::kStop;
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ Result<Success> ModaliasHandler::InsmodWithDeps(const std::string& module_name,
|
|||
return Insmod(dependencies[0], args);
|
||||
}
|
||||
|
||||
void ModaliasHandler::HandleModaliasEvent(const Uevent& uevent) {
|
||||
void ModaliasHandler::HandleUevent(const Uevent& uevent) {
|
||||
if (uevent.modalias.empty()) return;
|
||||
|
||||
for (const auto& [alias, module] : module_aliases_) {
|
||||
|
|
|
@ -16,22 +16,23 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "result.h"
|
||||
#include "uevent.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "result.h"
|
||||
#include "uevent.h"
|
||||
#include "uevent_handler.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
class ModaliasHandler {
|
||||
class ModaliasHandler : public UeventHandler {
|
||||
public:
|
||||
ModaliasHandler();
|
||||
~ModaliasHandler(){};
|
||||
virtual ~ModaliasHandler() = default;
|
||||
|
||||
void HandleModaliasEvent(const Uevent& uevent);
|
||||
void HandleUevent(const Uevent& uevent) override;
|
||||
|
||||
private:
|
||||
Result<Success> InsmodWithDeps(const std::string& module_name, const std::string& args);
|
||||
|
|
34
init/uevent_handler.h
Normal file
34
init/uevent_handler.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uevent.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
class UeventHandler {
|
||||
public:
|
||||
virtual ~UeventHandler() = default;
|
||||
|
||||
virtual void HandleUevent(const Uevent& uevent) = 0;
|
||||
|
||||
virtual void ColdbootDone() {}
|
||||
};
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
|
@ -38,6 +38,7 @@
|
|||
#include "firmware_handler.h"
|
||||
#include "modalias_handler.h"
|
||||
#include "selinux.h"
|
||||
#include "uevent_handler.h"
|
||||
#include "uevent_listener.h"
|
||||
#include "ueventd_parser.h"
|
||||
#include "util.h"
|
||||
|
@ -107,11 +108,10 @@ namespace init {
|
|||
|
||||
class ColdBoot {
|
||||
public:
|
||||
ColdBoot(UeventListener& uevent_listener, DeviceHandler& device_handler,
|
||||
ModaliasHandler& modalias_handler)
|
||||
ColdBoot(UeventListener& uevent_listener,
|
||||
std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers)
|
||||
: uevent_listener_(uevent_listener),
|
||||
device_handler_(device_handler),
|
||||
modalias_handler_(modalias_handler),
|
||||
uevent_handlers_(uevent_handlers),
|
||||
num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {}
|
||||
|
||||
void Run();
|
||||
|
@ -124,8 +124,7 @@ class ColdBoot {
|
|||
void WaitForSubProcesses();
|
||||
|
||||
UeventListener& uevent_listener_;
|
||||
DeviceHandler& device_handler_;
|
||||
ModaliasHandler& modalias_handler_;
|
||||
std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers_;
|
||||
|
||||
unsigned int num_handler_subprocesses_;
|
||||
std::vector<Uevent> uevent_queue_;
|
||||
|
@ -136,16 +135,16 @@ class ColdBoot {
|
|||
void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
|
||||
for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) {
|
||||
auto& uevent = uevent_queue_[i];
|
||||
device_handler_.HandleDeviceEvent(uevent);
|
||||
modalias_handler_.HandleModaliasEvent(uevent);
|
||||
|
||||
for (auto& uevent_handler : uevent_handlers_) {
|
||||
uevent_handler->HandleUevent(uevent);
|
||||
}
|
||||
}
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void ColdBoot::RegenerateUevents() {
|
||||
uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
|
||||
HandleFirmwareEvent(uevent);
|
||||
|
||||
uevent_queue_.emplace_back(std::move(uevent));
|
||||
return ListenerAction::kContinue;
|
||||
});
|
||||
|
@ -168,7 +167,6 @@ void ColdBoot::ForkSubProcesses() {
|
|||
|
||||
void ColdBoot::DoRestoreCon() {
|
||||
selinux_android_restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
|
||||
device_handler_.set_skip_restorecon(false);
|
||||
}
|
||||
|
||||
void ColdBoot::WaitForSubProcesses() {
|
||||
|
@ -234,8 +232,7 @@ int ueventd_main(int argc, char** argv) {
|
|||
SelinuxSetupKernelLogging();
|
||||
SelabelInitialize();
|
||||
|
||||
DeviceHandler device_handler;
|
||||
ModaliasHandler modalias_handler;
|
||||
std::vector<std::unique_ptr<UeventHandler>> uevent_handlers;
|
||||
UeventListener uevent_listener;
|
||||
|
||||
{
|
||||
|
@ -248,19 +245,27 @@ int ueventd_main(int argc, char** argv) {
|
|||
ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc", "/odm/ueventd.rc",
|
||||
"/ueventd." + hardware + ".rc"});
|
||||
|
||||
device_handler = DeviceHandler{std::move(ueventd_configuration.dev_permissions),
|
||||
std::move(ueventd_configuration.sysfs_permissions),
|
||||
std::move(ueventd_configuration.subsystems),
|
||||
fs_mgr_get_boot_devices(), true};
|
||||
uevent_handlers.emplace_back(std::make_unique<DeviceHandler>(
|
||||
std::move(ueventd_configuration.dev_permissions),
|
||||
std::move(ueventd_configuration.sysfs_permissions),
|
||||
std::move(ueventd_configuration.subsystems), fs_mgr_get_boot_devices(), true));
|
||||
uevent_handlers.emplace_back(std::make_unique<FirmwareHandler>(
|
||||
std::move(ueventd_configuration.firmware_directories)));
|
||||
|
||||
firmware_directories = ueventd_configuration.firmware_directories;
|
||||
if (ueventd_configuration.enable_modalias_handling) {
|
||||
uevent_handlers.emplace_back(std::make_unique<ModaliasHandler>());
|
||||
}
|
||||
}
|
||||
|
||||
if (access(COLDBOOT_DONE, F_OK) != 0) {
|
||||
ColdBoot cold_boot(uevent_listener, device_handler, modalias_handler);
|
||||
ColdBoot cold_boot(uevent_listener, uevent_handlers);
|
||||
cold_boot.Run();
|
||||
}
|
||||
|
||||
for (auto& uevent_handler : uevent_handlers) {
|
||||
uevent_handler->ColdbootDone();
|
||||
}
|
||||
|
||||
// We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now.
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
// Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN
|
||||
|
@ -268,10 +273,10 @@ int ueventd_main(int argc, char** argv) {
|
|||
while (waitpid(-1, nullptr, WNOHANG) > 0) {
|
||||
}
|
||||
|
||||
uevent_listener.Poll([&device_handler, &modalias_handler](const Uevent& uevent) {
|
||||
HandleFirmwareEvent(uevent);
|
||||
modalias_handler.HandleModaliasEvent(uevent);
|
||||
device_handler.HandleDeviceEvent(uevent);
|
||||
uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) {
|
||||
for (auto& uevent_handler : uevent_handlers) {
|
||||
uevent_handler->HandleUevent(uevent);
|
||||
}
|
||||
return ListenerAction::kContinue;
|
||||
});
|
||||
|
||||
|
|
|
@ -84,6 +84,23 @@ Result<Success> ParseFirmwareDirectoriesLine(std::vector<std::string>&& args,
|
|||
return Success();
|
||||
}
|
||||
|
||||
Result<Success> ParseModaliasHandlingLine(std::vector<std::string>&& args,
|
||||
bool* enable_modalias_handling) {
|
||||
if (args.size() != 2) {
|
||||
return Error() << "modalias_handling lines take exactly one parameter";
|
||||
}
|
||||
|
||||
if (args[1] == "enabled") {
|
||||
*enable_modalias_handling = true;
|
||||
} else if (args[1] == "disabled") {
|
||||
*enable_modalias_handling = false;
|
||||
} else {
|
||||
return Error() << "modalias_handling takes either 'enabled' or 'disabled' as a parameter";
|
||||
}
|
||||
|
||||
return Success();
|
||||
}
|
||||
|
||||
class SubsystemParser : public SectionParser {
|
||||
public:
|
||||
SubsystemParser(std::vector<Subsystem>* subsystems) : subsystems_(subsystems) {}
|
||||
|
@ -182,6 +199,9 @@ UeventdConfiguration ParseConfig(const std::vector<std::string>& configs) {
|
|||
parser.AddSingleLineParser("firmware_directories",
|
||||
std::bind(ParseFirmwareDirectoriesLine, _1,
|
||||
&ueventd_configuration.firmware_directories));
|
||||
parser.AddSingleLineParser("modalias_handling",
|
||||
std::bind(ParseModaliasHandlingLine, _1,
|
||||
&ueventd_configuration.enable_modalias_handling));
|
||||
|
||||
for (const auto& config : configs) {
|
||||
parser.ParseConfig(config);
|
||||
|
|
|
@ -30,6 +30,7 @@ struct UeventdConfiguration {
|
|||
std::vector<SysfsPermissions> sysfs_permissions;
|
||||
std::vector<Permissions> dev_permissions;
|
||||
std::vector<std::string> firmware_directories;
|
||||
bool enable_modalias_handling = false;
|
||||
};
|
||||
|
||||
UeventdConfiguration ParseConfig(const std::vector<std::string>& configs);
|
||||
|
|
Loading…
Reference in a new issue