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:
Tom Cherry 2018-08-01 13:12:20 -07:00
parent 081b710b2e
commit 457e28f129
11 changed files with 122 additions and 44 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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...

View file

@ -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

View file

@ -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;
}

View file

@ -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_) {

View file

@ -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
View 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

View file

@ -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;
});

View file

@ -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);

View file

@ -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);