Loading init/README.ueventd.md +10 −6 Original line number Diff line number Diff line Loading @@ -76,17 +76,17 @@ For example When `/dev/null` is created, its mode will be set to `0666`, its user to `root` and its group to `root`. The path can be modified using a ueventd.rc script and a `subsystem` section. There are three to set for a subsystem: the subsystem name, which device name to use, and which directory to place the device in. The section takes the below format of The path can be modified using a ueventd.rc script and a `subsystem` and/or `driver` section. There are three options to set for a subsystem or driver: the name, which device name to use, and which directory to place the device in. The section takes the below format of subsystem <subsystem_name> devname uevent_devname|uevent_devpath [dirname <directory>] `subsystem_name` is used to match uevent `SUBSYSTEM` value `subsystem_name` is used to match the uevent `SUBSYSTEM` value. `devname` takes one of three options `devname` takes one of three options: 1. `uevent_devname` specifies that the name of the node will be the uevent `DEVNAME` 2. `uevent_devpath` specifies that the name of the node will be basename uevent `DEVPATH` 3. `sys_name` specifies that the name of the node will be the contents of `/sys/DEVPATH/name` Loading @@ -99,9 +99,13 @@ For example subsystem sound devname uevent_devpath dirname /dev/snd Indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/<basename uevent indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/<basename uevent DEVPATH>`. The `driver` section has the exact same structure as a `subsystem` section, but will instead match the `DRIVER` value in a `bind`/`unbind` uevent. However, the `driver` section will be ignored for block devices. ## /sys ---- Ueventd by default takes no action for `/sys`, however it can be instructed to set permissions for Loading init/block_dev_initializer.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,8 @@ BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) auto boot_devices = android::fs_mgr::GetBootDevices(); device_handler_ = std::make_unique<DeviceHandler>( std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{}, std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), false); std::vector<Subsystem>{}, std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), false); } // If boot_part_uuid is specified, use it to set boot_devices Loading init/devices.cpp +69 −3 Original line number Diff line number Diff line Loading @@ -345,6 +345,26 @@ bool DeviceHandler::FindScsiDevice(const std::string& path, std::string* scsi_de return FindSubsystemDevice(path, scsi_device_path, subsystem_paths); } void DeviceHandler::TrackDeviceUevent(const Uevent& uevent) { // No need to track any events if we won't bother handling any bind events // later. if (drivers_.size() == 0) return; // Only track add, and not for block devices. We don't track remove because // unbind events may arrive after remove events, so unbind will be the // trigger to untrack those events. if ((uevent.action != "add") || uevent.subsystem == "block" || (uevent.major < 0 || uevent.minor < 0)) { return; } std::string path = sysfs_mount_point_ + uevent.path + "/device"; std::string device; if (!Realpath(path, &device)) return; tracked_uevents_.emplace_back(uevent, device); } void DeviceHandler::FixupSysPermissions(const std::string& upath, const std::string& subsystem) const { // upaths omit the "/sys" that paths in this list Loading Loading @@ -664,12 +684,53 @@ bool DeviceHandler::CheckUeventForBootPartUuid(const Uevent& uevent) { return true; } void DeviceHandler::HandleBindInternal(std::string driver_name, std::string action, const Uevent& uevent) { if (uevent.subsystem == "block") { LOG(FATAL) << "Tried to handle bind event for block device"; } // Get tracked uevents for all devices that have this uevent's path as // their canonical device path. Then handle those again if their driver // is one of the ones we're interested in. const auto driver = std::find(drivers_.cbegin(), drivers_.cend(), driver_name); if (driver == drivers_.cend()) return; std::string bind_path = sysfs_mount_point_ + uevent.path; for (const TrackedUevent& tracked : tracked_uevents_) { if (tracked.canonical_device_path != bind_path) continue; LOG(VERBOSE) << "Propagating " << uevent.action << " as " << action << " for " << uevent.path; std::string devpath = driver->ParseDevPath(tracked.uevent); mkdir_recursive(Dirname(devpath), 0755); HandleDevice(action, devpath, false, tracked.uevent.major, tracked.uevent.minor, std::vector<std::string>{}); } } void DeviceHandler::HandleUevent(const Uevent& uevent) { if (uevent.action == "add" || uevent.action == "change" || uevent.action == "bind" || uevent.action == "online") { FixupSysPermissions(uevent.path, uevent.subsystem); } if (uevent.action == "bind") { bound_drivers_[uevent.path] = uevent.driver; HandleBindInternal(uevent.driver, "add", uevent); return; } else if (uevent.action == "unbind") { if (bound_drivers_.count(uevent.path) == 0) return; HandleBindInternal(bound_drivers_[uevent.path], "remove", uevent); std::string sys_path = sysfs_mount_point_ + uevent.path; std::erase_if(tracked_uevents_, [&sys_path](const TrackedUevent& tracked) { return sys_path == tracked.canonical_device_path; }); return; } // if it's not a /dev device, nothing to do if (uevent.major < 0 || uevent.minor < 0) return; Loading @@ -677,6 +738,8 @@ void DeviceHandler::HandleUevent(const Uevent& uevent) { std::vector<std::string> links; bool block = false; TrackDeviceUevent(uevent); if (uevent.subsystem == "block") { block = true; devpath = "/dev/block/" + Basename(uevent.path); Loading Loading @@ -725,10 +788,12 @@ void DeviceHandler::ColdbootDone() { DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions, std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> subsystems, std::set<std::string> boot_devices, std::string boot_part_uuid, bool skip_restorecon) std::vector<Subsystem> drivers, std::vector<Subsystem> subsystems, std::set<std::string> boot_devices, std::string boot_part_uuid, bool skip_restorecon) : dev_permissions_(std::move(dev_permissions)), sysfs_permissions_(std::move(sysfs_permissions)), drivers_(std::move(drivers)), subsystems_(std::move(subsystems)), boot_devices_(std::move(boot_devices)), boot_part_uuid_(boot_part_uuid), Loading @@ -744,7 +809,8 @@ DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions, DeviceHandler::DeviceHandler() : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{}, std::set<std::string>{}, "", false) {} std::vector<Subsystem>{}, std::vector<Subsystem>{}, std::set<std::string>{}, "", false) {} } // namespace init } // namespace android init/devices.h +14 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <sys/types.h> #include <algorithm> #include <map> #include <set> #include <string> #include <vector> Loading Loading @@ -128,7 +129,7 @@ class DeviceHandler : public UeventHandler { DeviceHandler(); DeviceHandler(std::vector<Permissions> dev_permissions, std::vector<SysfsPermissions> sysfs_permissions, std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> drivers, std::vector<Subsystem> subsystems, std::set<std::string> boot_devices, std::string boot_part_uuid, bool skip_restorecon); virtual ~DeviceHandler() = default; Loading @@ -145,6 +146,11 @@ class DeviceHandler : public UeventHandler { bool IsBootDevice(const Uevent& uevent) const; private: struct TrackedUevent { Uevent uevent; std::string canonical_device_path; }; void ColdbootDone() override; BlockDeviceInfo GetBlockDeviceInfo(const std::string& uevent_path) const; bool FindSubsystemDevice(std::string path, std::string* device_path, Loading @@ -163,14 +169,21 @@ class DeviceHandler : public UeventHandler { void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const; void HandleAshmemUevent(const Uevent& uevent); void TrackDeviceUevent(const Uevent& uevent); void HandleBindInternal(std::string driver_name, std::string action, const Uevent& uevent); std::vector<Permissions> dev_permissions_; std::vector<SysfsPermissions> sysfs_permissions_; std::vector<Subsystem> drivers_; std::vector<Subsystem> subsystems_; std::set<std::string> boot_devices_; std::string boot_part_uuid_; bool found_boot_part_uuid_; bool skip_restorecon_; std::string sysfs_mount_point_; std::vector<TrackedUevent> tracked_uevents_; std::map<std::string, std::string> bound_drivers_; }; // Exposed for testing Loading init/uevent.h +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ struct Uevent { std::string action; std::string path; std::string subsystem; std::string driver; std::string firmware; std::string partition_name; std::string partition_uuid; Loading Loading
init/README.ueventd.md +10 −6 Original line number Diff line number Diff line Loading @@ -76,17 +76,17 @@ For example When `/dev/null` is created, its mode will be set to `0666`, its user to `root` and its group to `root`. The path can be modified using a ueventd.rc script and a `subsystem` section. There are three to set for a subsystem: the subsystem name, which device name to use, and which directory to place the device in. The section takes the below format of The path can be modified using a ueventd.rc script and a `subsystem` and/or `driver` section. There are three options to set for a subsystem or driver: the name, which device name to use, and which directory to place the device in. The section takes the below format of subsystem <subsystem_name> devname uevent_devname|uevent_devpath [dirname <directory>] `subsystem_name` is used to match uevent `SUBSYSTEM` value `subsystem_name` is used to match the uevent `SUBSYSTEM` value. `devname` takes one of three options `devname` takes one of three options: 1. `uevent_devname` specifies that the name of the node will be the uevent `DEVNAME` 2. `uevent_devpath` specifies that the name of the node will be basename uevent `DEVPATH` 3. `sys_name` specifies that the name of the node will be the contents of `/sys/DEVPATH/name` Loading @@ -99,9 +99,13 @@ For example subsystem sound devname uevent_devpath dirname /dev/snd Indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/<basename uevent indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/<basename uevent DEVPATH>`. The `driver` section has the exact same structure as a `subsystem` section, but will instead match the `DRIVER` value in a `bind`/`unbind` uevent. However, the `driver` section will be ignored for block devices. ## /sys ---- Ueventd by default takes no action for `/sys`, however it can be instructed to set permissions for Loading
init/block_dev_initializer.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,8 @@ BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) auto boot_devices = android::fs_mgr::GetBootDevices(); device_handler_ = std::make_unique<DeviceHandler>( std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{}, std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), false); std::vector<Subsystem>{}, std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), false); } // If boot_part_uuid is specified, use it to set boot_devices Loading
init/devices.cpp +69 −3 Original line number Diff line number Diff line Loading @@ -345,6 +345,26 @@ bool DeviceHandler::FindScsiDevice(const std::string& path, std::string* scsi_de return FindSubsystemDevice(path, scsi_device_path, subsystem_paths); } void DeviceHandler::TrackDeviceUevent(const Uevent& uevent) { // No need to track any events if we won't bother handling any bind events // later. if (drivers_.size() == 0) return; // Only track add, and not for block devices. We don't track remove because // unbind events may arrive after remove events, so unbind will be the // trigger to untrack those events. if ((uevent.action != "add") || uevent.subsystem == "block" || (uevent.major < 0 || uevent.minor < 0)) { return; } std::string path = sysfs_mount_point_ + uevent.path + "/device"; std::string device; if (!Realpath(path, &device)) return; tracked_uevents_.emplace_back(uevent, device); } void DeviceHandler::FixupSysPermissions(const std::string& upath, const std::string& subsystem) const { // upaths omit the "/sys" that paths in this list Loading Loading @@ -664,12 +684,53 @@ bool DeviceHandler::CheckUeventForBootPartUuid(const Uevent& uevent) { return true; } void DeviceHandler::HandleBindInternal(std::string driver_name, std::string action, const Uevent& uevent) { if (uevent.subsystem == "block") { LOG(FATAL) << "Tried to handle bind event for block device"; } // Get tracked uevents for all devices that have this uevent's path as // their canonical device path. Then handle those again if their driver // is one of the ones we're interested in. const auto driver = std::find(drivers_.cbegin(), drivers_.cend(), driver_name); if (driver == drivers_.cend()) return; std::string bind_path = sysfs_mount_point_ + uevent.path; for (const TrackedUevent& tracked : tracked_uevents_) { if (tracked.canonical_device_path != bind_path) continue; LOG(VERBOSE) << "Propagating " << uevent.action << " as " << action << " for " << uevent.path; std::string devpath = driver->ParseDevPath(tracked.uevent); mkdir_recursive(Dirname(devpath), 0755); HandleDevice(action, devpath, false, tracked.uevent.major, tracked.uevent.minor, std::vector<std::string>{}); } } void DeviceHandler::HandleUevent(const Uevent& uevent) { if (uevent.action == "add" || uevent.action == "change" || uevent.action == "bind" || uevent.action == "online") { FixupSysPermissions(uevent.path, uevent.subsystem); } if (uevent.action == "bind") { bound_drivers_[uevent.path] = uevent.driver; HandleBindInternal(uevent.driver, "add", uevent); return; } else if (uevent.action == "unbind") { if (bound_drivers_.count(uevent.path) == 0) return; HandleBindInternal(bound_drivers_[uevent.path], "remove", uevent); std::string sys_path = sysfs_mount_point_ + uevent.path; std::erase_if(tracked_uevents_, [&sys_path](const TrackedUevent& tracked) { return sys_path == tracked.canonical_device_path; }); return; } // if it's not a /dev device, nothing to do if (uevent.major < 0 || uevent.minor < 0) return; Loading @@ -677,6 +738,8 @@ void DeviceHandler::HandleUevent(const Uevent& uevent) { std::vector<std::string> links; bool block = false; TrackDeviceUevent(uevent); if (uevent.subsystem == "block") { block = true; devpath = "/dev/block/" + Basename(uevent.path); Loading Loading @@ -725,10 +788,12 @@ void DeviceHandler::ColdbootDone() { DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions, std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> subsystems, std::set<std::string> boot_devices, std::string boot_part_uuid, bool skip_restorecon) std::vector<Subsystem> drivers, std::vector<Subsystem> subsystems, std::set<std::string> boot_devices, std::string boot_part_uuid, bool skip_restorecon) : dev_permissions_(std::move(dev_permissions)), sysfs_permissions_(std::move(sysfs_permissions)), drivers_(std::move(drivers)), subsystems_(std::move(subsystems)), boot_devices_(std::move(boot_devices)), boot_part_uuid_(boot_part_uuid), Loading @@ -744,7 +809,8 @@ DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions, DeviceHandler::DeviceHandler() : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{}, std::set<std::string>{}, "", false) {} std::vector<Subsystem>{}, std::vector<Subsystem>{}, std::set<std::string>{}, "", false) {} } // namespace init } // namespace android
init/devices.h +14 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <sys/types.h> #include <algorithm> #include <map> #include <set> #include <string> #include <vector> Loading Loading @@ -128,7 +129,7 @@ class DeviceHandler : public UeventHandler { DeviceHandler(); DeviceHandler(std::vector<Permissions> dev_permissions, std::vector<SysfsPermissions> sysfs_permissions, std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> drivers, std::vector<Subsystem> subsystems, std::set<std::string> boot_devices, std::string boot_part_uuid, bool skip_restorecon); virtual ~DeviceHandler() = default; Loading @@ -145,6 +146,11 @@ class DeviceHandler : public UeventHandler { bool IsBootDevice(const Uevent& uevent) const; private: struct TrackedUevent { Uevent uevent; std::string canonical_device_path; }; void ColdbootDone() override; BlockDeviceInfo GetBlockDeviceInfo(const std::string& uevent_path) const; bool FindSubsystemDevice(std::string path, std::string* device_path, Loading @@ -163,14 +169,21 @@ class DeviceHandler : public UeventHandler { void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const; void HandleAshmemUevent(const Uevent& uevent); void TrackDeviceUevent(const Uevent& uevent); void HandleBindInternal(std::string driver_name, std::string action, const Uevent& uevent); std::vector<Permissions> dev_permissions_; std::vector<SysfsPermissions> sysfs_permissions_; std::vector<Subsystem> drivers_; std::vector<Subsystem> subsystems_; std::set<std::string> boot_devices_; std::string boot_part_uuid_; bool found_boot_part_uuid_; bool skip_restorecon_; std::string sysfs_mount_point_; std::vector<TrackedUevent> tracked_uevents_; std::map<std::string, std::string> bound_drivers_; }; // Exposed for testing Loading
init/uevent.h +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ struct Uevent { std::string action; std::string path; std::string subsystem; std::string driver; std::string firmware; std::string partition_name; std::string partition_uuid; Loading