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
diff --git a/init/devices.cpp b/init/devices.cpp
index ed4a739..ba08180 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -372,7 +372,7 @@
}
}
-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 @@
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,
diff --git a/init/devices.h b/init/devices.h
index 0be660f..9d39eaa 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -29,6 +29,7 @@
#include <selinux/label.h>
#include "uevent.h"
+#include "uevent_handler.h"
namespace android {
namespace init {
@@ -105,7 +106,7 @@
std::string dir_name_ = "/dev";
};
-class DeviceHandler {
+class DeviceHandler : public UeventHandler {
public:
friend class DeviceHandlerTester;
@@ -113,11 +114,12 @@
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;
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 28bda34..740e82c 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -35,8 +35,6 @@
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 @@
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 @@
}
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 @@
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...
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index 6081511..3996096 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -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
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 43075b2..41e8fff 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -206,7 +206,7 @@
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 @@
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 @@
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;
}
diff --git a/init/modalias_handler.cpp b/init/modalias_handler.cpp
index 1734a7e..1e0db57 100644
--- a/init/modalias_handler.cpp
+++ b/init/modalias_handler.cpp
@@ -139,7 +139,7 @@
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_) {
diff --git a/init/modalias_handler.h b/init/modalias_handler.h
index e79da32..3247c86 100644
--- a/init/modalias_handler.h
+++ b/init/modalias_handler.h
@@ -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);
diff --git a/init/uevent_handler.h b/init/uevent_handler.h
new file mode 100644
index 0000000..75d1990
--- /dev/null
+++ b/init/uevent_handler.h
@@ -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
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index e9d829b..95be6af 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -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 @@
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 @@
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 @@
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::DoRestoreCon() {
selinux_android_restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
- device_handler_.set_skip_restorecon(false);
}
void ColdBoot::WaitForSubProcesses() {
@@ -234,8 +232,7 @@
SelinuxSetupKernelLogging();
SelabelInitialize();
- DeviceHandler device_handler;
- ModaliasHandler modalias_handler;
+ std::vector<std::unique_ptr<UeventHandler>> uevent_handlers;
UeventListener uevent_listener;
{
@@ -248,19 +245,27 @@
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 @@
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;
});
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 54b0d16..677938e 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -84,6 +84,23 @@
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 @@
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);
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 343d58b..7d30edf 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -30,6 +30,7 @@
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);