From 6a5db6838514d92d9d2361810f9b96d5039e2801 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 15 Nov 2024 01:06:55 +0000 Subject: [PATCH 1/5] Remove non-UTF8 characters from string fields. The string type in the tombstone proto does not support non-UTF8 characters. Therefore, use the oct_encode function to encode the abort_message field and message field from LogMessage. Fix up stl includes, add ones that were missing and remove those not being used. Add new unit test to verify that the abort and log messages are sanitized. Bug: 279496937 Bug: 377940849 Bug: 378185483 Test: All unit tests pass. Test: Ran pbtombstone on a crash with non-UTF8 characters and verified Test: it processes properly after this change and fails before the change. Change-Id: I3554d56caf9fcbfc410b4d554f6c3b4888b37e28 --- debuggerd/debuggerd_test.cpp | 27 +++++++++++++++++++ .../include/libdebuggerd/utility_host.h | 2 ++ debuggerd/libdebuggerd/tombstone_proto.cpp | 9 +++++-- .../libdebuggerd/tombstone_proto_to_text.cpp | 26 +++--------------- debuggerd/libdebuggerd/utility_host.cpp | 23 ++++++++++++++++ 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index 13c8d70b5..5bdc94646 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -3302,3 +3302,30 @@ TEST_F(CrasherTest, log_with_newline) { ASSERT_MATCH(result, ":\\s*This line has a newline."); ASSERT_MATCH(result, ":\\s*This is on the next line."); } + +TEST_F(CrasherTest, log_with_non_utf8) { + StartProcess([]() { LOG(FATAL) << "Invalid UTF-8: \xA0\xB0\xC0\xD0 and some other data."; }); + + unique_fd output_fd; + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGABRT); + int intercept_result; + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + // Verify the abort message is sanitized properly. + size_t pos = result.find( + "Abort message: 'Invalid UTF-8: " + "\x5C\x32\x34\x30\x5C\x32\x36\x30\x5C\x33\x30\x30\x5C\x33\x32\x30 and some other data.'"); + EXPECT_TRUE(pos != std::string::npos) << "Couldn't find sanitized abort message: " << result; + + // Make sure that the log message is sanitized properly too. + EXPECT_TRUE( + result.find("Invalid UTF-8: \x5C\x32\x34\x30\x5C\x32\x36\x30\x5C\x33\x30\x30\x5C\x33\x32\x30 " + "and some other data.", + pos + 30) != std::string::npos) + << "Couldn't find sanitized log message: " << result; +} diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h index 43fb8bdc1..df22e017c 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h @@ -29,3 +29,5 @@ constexpr size_t kTagGranuleSize = 16; // Number of rows and columns to display in an MTE tag dump. constexpr size_t kNumTagColumns = 16; constexpr size_t kNumTagRows = 16; + +std::string oct_encode(const std::string& data); diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index d59358c65..ef303f065 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -34,10 +34,13 @@ #include #include +#include #include #include #include #include +#include +#include #include @@ -463,7 +466,8 @@ static void dump_abort_message(Tombstone* tombstone, } msg.resize(index); - tombstone->set_abort_message(msg); + // Make sure only UTF8 characters are present since abort_message is a string. + tombstone->set_abort_message(oct_encode(msg)); } static void dump_open_fds(Tombstone* tombstone, const OpenFilesList* open_files) { @@ -771,7 +775,8 @@ static void dump_log_file(Tombstone* tombstone, const char* logger, pid_t pid) { log_msg->set_tid(log_entry.entry.tid); log_msg->set_priority(prio); log_msg->set_tag(tag); - log_msg->set_message(msg); + // Make sure only UTF8 characters are present since message is a string. + log_msg->set_message(oct_encode(msg)); } while ((msg = nl)); } android_logger_list_free(logger_list); diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index fedafc0c3..e885c5a73 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -19,9 +19,9 @@ #include -#include +#include #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ #include #include +#include "libdebuggerd/utility_host.h" #include "tombstone.pb.h" using android::base::StringAppendF; @@ -418,27 +419,6 @@ static void print_memory_maps(CallbackType callback, const Tombstone& tombstone) } } -static std::string oct_encode(const std::string& data) { - std::string oct_encoded; - oct_encoded.reserve(data.size()); - - // N.B. the unsigned here is very important, otherwise e.g. \255 would render as - // \-123 (and overflow our buffer). - for (unsigned char c : data) { - if (isprint(c)) { - oct_encoded += c; - } else { - std::string oct_digits("\\\0\0\0", 4); - // char is encodable in 3 oct digits - static_assert(std::numeric_limits::max() <= 8 * 8 * 8); - auto [ptr, ec] = std::to_chars(oct_digits.data() + 1, oct_digits.data() + 4, c, 8); - oct_digits.resize(ptr - oct_digits.data()); - oct_encoded += oct_digits; - } - } - return oct_encoded; -} - static void print_main_thread(CallbackType callback, SymbolizeCallbackType symbolize, const Tombstone& tombstone, const Thread& thread) { print_thread_header(callback, tombstone, thread, true); diff --git a/debuggerd/libdebuggerd/utility_host.cpp b/debuggerd/libdebuggerd/utility_host.cpp index 72a560cfe..4efa03c8c 100644 --- a/debuggerd/libdebuggerd/utility_host.cpp +++ b/debuggerd/libdebuggerd/utility_host.cpp @@ -18,6 +18,8 @@ #include +#include +#include #include #include @@ -99,3 +101,24 @@ std::string describe_pac_enabled_keys(long value) { DESCRIBE_FLAG(PR_PAC_APGAKEY); return describe_end(value, desc); } + +std::string oct_encode(const std::string& data) { + std::string oct_encoded; + oct_encoded.reserve(data.size()); + + // N.B. the unsigned here is very important, otherwise e.g. \255 would render as + // \-123 (and overflow our buffer). + for (unsigned char c : data) { + if (isprint(c)) { + oct_encoded += c; + } else { + std::string oct_digits("\\\0\0\0", 4); + // char is encodable in 3 oct digits + static_assert(std::numeric_limits::max() <= 8 * 8 * 8); + auto [ptr, ec] = std::to_chars(oct_digits.data() + 1, oct_digits.data() + 4, c, 8); + oct_digits.resize(ptr - oct_digits.data()); + oct_encoded += oct_digits; + } + } + return oct_encoded; +} From 28b2556e90dcad4e2ecaabb2e8f5413986dce1de Mon Sep 17 00:00:00 2001 From: Aeric Date: Mon, 18 Nov 2024 17:30:46 +0800 Subject: [PATCH 2/5] Fix typo of snapuserd_verify.h "advisible" should be "advisable" "fucntionality" should be "functionality" Bug: 379603290 Test: build pass Change-Id: I6c95f2b186f479ba51df8603ce87c0522e91bf64 --- .../libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h index 7c9908515..b300a7000 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h @@ -62,8 +62,8 @@ class UpdateVerify { * (/proc/pressure/{cpu,memory}; and monitoring the Inactive(file) and * Active(file) pages from /proc/meminfo. * - * Additionally, for low memory devices, it is advisible to use O_DIRECT - * fucntionality for source block device. + * Additionally, for low memory devices, it is advisable to use O_DIRECT + * functionality for source block device. */ int kMinThreadsToVerify = 1; int kMaxThreadsToVerify = 3; From f1d00f0f2a897f76060b5083b9b0f9c051b16c51 Mon Sep 17 00:00:00 2001 From: Neill Kapron Date: Tue, 19 Nov 2024 02:13:33 +0000 Subject: [PATCH 3/5] libcutils: create rust bindings for android ids For work on the new rust based bpfloader, we need access to the IDs in android_filesystem_config.h for owner/group permissions of pinned bpf programs and maps. Create android_ids crate to expose this information to rust. Bug: 359646531 Test: Manual Change-Id: Iee827d8a80a82fbee02a76280668071713625abf Signed-off-by: Neill Kapron --- libcutils/Android.bp | 11 +++++++++++ libcutils/rust/aid_bindings.h | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 libcutils/rust/aid_bindings.h diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 10392889d..ec9b75493 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -21,6 +21,17 @@ filegroup { srcs: ["include/private/android_filesystem_config.h"], } +rust_bindgen { + name: "libandroid_ids", + crate_name: "android_ids", + source_stem: "bindings", + wrapper_src: "rust/aid_bindings.h", + header_libs: ["libcutils_headers"], + visibility: [ + "//system/bpf/loader", + ], +} + cc_defaults { name: "libcutils_defaults", cflags: [ diff --git a/libcutils/rust/aid_bindings.h b/libcutils/rust/aid_bindings.h new file mode 100644 index 000000000..1b175a26f --- /dev/null +++ b/libcutils/rust/aid_bindings.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2024 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. + */ +#include From 668ffc395d0c83c9e9cdcca972e35e936a5f85f0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 18 Nov 2024 19:23:45 -0800 Subject: [PATCH 4/5] snapuserd: Use GTEST_SKIP in snapuserd_test. The test harness treats an early exit as a failure, so use GTEST_SKIP() instead. Bug: 379242140 Test: vts_snapuserd_test Change-Id: I25351bb7ebf65e6c56865662d297feb4a1f635b3 --- .../user-space-merge/snapuserd_test.cpp | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp index 4dfb9bf4e..469fd091a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -82,6 +82,8 @@ class SnapuserdTestBase : public ::testing::TestWithParam { unique_fd GetCowFd() { return unique_fd{dup(cow_system_->fd)}; } + bool ShouldSkipSetUp(); + std::unique_ptr harness_; size_t size_ = 10_MiB; int total_base_size_ = 0; @@ -97,6 +99,10 @@ class SnapuserdTestBase : public ::testing::TestWithParam { }; void SnapuserdTestBase::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } + #if __ANDROID__ harness_ = std::make_unique(); #else @@ -104,6 +110,16 @@ void SnapuserdTestBase::SetUp() { #endif } +bool SnapuserdTestBase::ShouldSkipSetUp() { +#ifdef __ANDROID__ + if (!android::snapshot::CanUseUserspaceSnapshots() || + android::snapshot::IsVendorFromAndroid12()) { + return true; + } +#endif + return false; +} + void SnapuserdTestBase::TearDown() { cow_system_ = nullptr; } @@ -302,6 +318,9 @@ class SnapuserdTest : public SnapuserdTestBase { }; void SnapuserdTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); handlers_ = std::make_unique(); } @@ -312,6 +331,9 @@ void SnapuserdTest::TearDown() { } void SnapuserdTest::Shutdown() { + if (!handlers_) { + return; + } if (dmuser_dev_) { ASSERT_TRUE(dmuser_dev_->Destroy()); } @@ -1181,6 +1203,9 @@ void SnapuserdVariableBlockSizeTest::ReadSnapshotWithVariableBlockSize() { } void SnapuserdVariableBlockSizeTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTest::SetUp()); } @@ -1244,6 +1269,9 @@ void HandlerTest::InitializeDevice() { } void HandlerTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); ASSERT_NO_FATAL_FAILURE(SetUpV2Cow()); @@ -1251,6 +1279,9 @@ void HandlerTest::SetUp() { } void HandlerTest::TearDown() { + if (ShouldSkipSetUp()) { + return; + } ASSERT_TRUE(factory_.DeleteQueue(system_device_ctrl_name_)); ASSERT_TRUE(handler_thread_.get()); SnapuserdTestBase::TearDown(); @@ -1326,6 +1357,9 @@ class HandlerTestV3 : public HandlerTest { }; void HandlerTestV3::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); ASSERT_NO_FATAL_FAILURE(SetUpV3Cow()); @@ -1530,14 +1564,6 @@ INSTANTIATE_TEST_SUITE_P(Io, HandlerTest, ::testing::ValuesIn(GetTestConfigs())) int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); -#ifdef __ANDROID__ - if (!android::snapshot::CanUseUserspaceSnapshots() || - android::snapshot::IsVendorFromAndroid12()) { - std::cerr << "snapuserd_test not supported on this device\n"; - return 0; - } -#endif - gflags::ParseCommandLineFlags(&argc, &argv, false); return RUN_ALL_TESTS(); From d17d5c585efe81d2e8a048efb919c2b7faabcb4a Mon Sep 17 00:00:00 2001 From: Eric Caruso Date: Mon, 28 Oct 2024 15:30:11 -0400 Subject: [PATCH 5/5] ueventd: add support for driver section in ueventd.rc Allow ueventd configuration to specify what to do with devices based on driver. This responds to bind events and treats them similarly to add events. The format of the driver stanza is exactly the same as that of the subsystem stanza. Bug: 376900376 Test: set up cbc_mbim driver stanza and ensure it properly creates and destroys device nodes when a USB device with that driver appears and disappears or is bound and unbound Change-Id: I31f5c91bd074d14075b74fe7beefaa6ac07a7ac9 --- init/README.ueventd.md | 16 +++++--- init/block_dev_initializer.cpp | 3 +- init/devices.cpp | 72 ++++++++++++++++++++++++++++++++-- init/devices.h | 15 ++++++- init/uevent.h | 1 + init/uevent_listener.cpp | 4 ++ init/ueventd.cpp | 4 +- init/ueventd_parser.cpp | 2 + init/ueventd_parser.h | 1 + init/ueventd_parser_test.cpp | 56 +++++++++++++++++++++----- 10 files changed, 151 insertions(+), 23 deletions(-) diff --git a/init/README.ueventd.md b/init/README.ueventd.md index aac4acb6a..0e84c6f5f 100644 --- a/init/README.ueventd.md +++ b/init/README.ueventd.md @@ -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 devname uevent_devname|uevent_devpath [dirname ] -`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` @@ -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/`. +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 diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index 7f83037ae..deb68e9ac 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -33,7 +33,8 @@ BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) auto boot_devices = android::fs_mgr::GetBootDevices(); device_handler_ = std::make_unique( std::vector{}, std::vector{}, std::vector{}, - std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), false); + std::vector{}, std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), + false); } // If boot_part_uuid is specified, use it to set boot_devices diff --git a/init/devices.cpp b/init/devices.cpp index fafa58f45..aeaa43133 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -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 @@ -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{}); + } +} + 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; @@ -677,6 +738,8 @@ void DeviceHandler::HandleUevent(const Uevent& uevent) { std::vector links; bool block = false; + TrackDeviceUevent(uevent); + if (uevent.subsystem == "block") { block = true; devpath = "/dev/block/" + Basename(uevent.path); @@ -725,10 +788,12 @@ void DeviceHandler::ColdbootDone() { DeviceHandler::DeviceHandler(std::vector dev_permissions, std::vector sysfs_permissions, - std::vector subsystems, std::set boot_devices, - std::string boot_part_uuid, bool skip_restorecon) + std::vector drivers, std::vector subsystems, + std::set 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), @@ -744,7 +809,8 @@ DeviceHandler::DeviceHandler(std::vector dev_permissions, DeviceHandler::DeviceHandler() : DeviceHandler(std::vector{}, std::vector{}, - std::vector{}, std::set{}, "", false) {} + std::vector{}, std::vector{}, std::set{}, "", + false) {} } // namespace init } // namespace android diff --git a/init/devices.h b/init/devices.h index b8f8e542f..69a244978 100644 --- a/init/devices.h +++ b/init/devices.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -128,7 +129,7 @@ class DeviceHandler : public UeventHandler { DeviceHandler(); DeviceHandler(std::vector dev_permissions, - std::vector sysfs_permissions, + std::vector sysfs_permissions, std::vector drivers, std::vector subsystems, std::set boot_devices, std::string boot_part_uuid, bool skip_restorecon); virtual ~DeviceHandler() = default; @@ -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, @@ -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 dev_permissions_; std::vector sysfs_permissions_; + std::vector drivers_; std::vector subsystems_; std::set boot_devices_; std::string boot_part_uuid_; bool found_boot_part_uuid_; bool skip_restorecon_; std::string sysfs_mount_point_; + + std::vector tracked_uevents_; + std::map bound_drivers_; }; // Exposed for testing diff --git a/init/uevent.h b/init/uevent.h index c8ca52aaf..e7ed2266e 100644 --- a/init/uevent.h +++ b/init/uevent.h @@ -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; diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp index 97f3de640..d329c174f 100644 --- a/init/uevent_listener.cpp +++ b/init/uevent_listener.cpp @@ -36,6 +36,7 @@ static void ParseEvent(const char* msg, Uevent* uevent) { uevent->action.clear(); uevent->path.clear(); uevent->subsystem.clear(); + uevent->driver.clear(); uevent->firmware.clear(); uevent->partition_name.clear(); uevent->device_name.clear(); @@ -51,6 +52,9 @@ static void ParseEvent(const char* msg, Uevent* uevent) { } else if (!strncmp(msg, "SUBSYSTEM=", 10)) { msg += 10; uevent->subsystem = msg; + } else if (!strncmp(msg, "DRIVER=", 7)) { + msg += 7; + uevent->driver = msg; } else if (!strncmp(msg, "FIRMWARE=", 9)) { msg += 9; uevent->firmware = msg; diff --git a/init/ueventd.cpp b/init/ueventd.cpp index 286e47266..cb6b851d6 100644 --- a/init/ueventd.cpp +++ b/init/ueventd.cpp @@ -364,8 +364,8 @@ int ueventd_main(int argc, char** argv) { std::unique_ptr device_handler = std::make_unique( std::move(ueventd_configuration.dev_permissions), std::move(ueventd_configuration.sysfs_permissions), - std::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), - android::fs_mgr::GetBootPartUuid(), true); + std::move(ueventd_configuration.drivers), std::move(ueventd_configuration.subsystems), + android::fs_mgr::GetBootDevices(), android::fs_mgr::GetBootPartUuid(), true); uevent_listener.RegenerateUevents([&](const Uevent& uevent) -> ListenerAction { bool uuid_check_done = device_handler->CheckUeventForBootPartUuid(uevent); return uuid_check_done ? ListenerAction::kStop : ListenerAction::kContinue; diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp index 4395d8838..097ef09d7 100644 --- a/init/ueventd_parser.cpp +++ b/init/ueventd_parser.cpp @@ -264,6 +264,8 @@ UeventdConfiguration ParseConfig(const std::vector& configs) { parser.AddSectionParser("import", std::make_unique(&parser)); parser.AddSectionParser("subsystem", std::make_unique(&ueventd_configuration.subsystems)); + parser.AddSectionParser("driver", + std::make_unique(&ueventd_configuration.drivers)); using namespace std::placeholders; parser.AddSingleLineParser( diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h index 81f4e9d54..ffe6072df 100644 --- a/init/ueventd_parser.h +++ b/init/ueventd_parser.h @@ -27,6 +27,7 @@ namespace init { struct UeventdConfiguration { std::vector subsystems; + std::vector drivers; std::vector sysfs_permissions; std::vector dev_permissions; std::vector firmware_directories; diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp index 41924e235..6d910398a 100644 --- a/init/ueventd_parser_test.cpp +++ b/init/ueventd_parser_test.cpp @@ -106,7 +106,32 @@ subsystem test_devpath_dirname {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}}; - TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}, {}}); + TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}, {}, {}}); +} + +TEST(ueventd_parser, Drivers) { + auto ueventd_file = R"( +driver test_devname + devname uevent_devname + +driver test_devpath_no_dirname + devname uevent_devpath + +driver test_devname2 + devname uevent_devname + +driver test_devpath_dirname + devname uevent_devpath + dirname /dev/graphics +)"; + + auto drivers = std::vector{ + {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, + {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"}, + {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, + {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}}; + + TestUeventdFile(ueventd_file, {{}, drivers, {}, {}, {}, {}, {}, {}}); } TEST(ueventd_parser, Permissions) { @@ -132,7 +157,7 @@ TEST(ueventd_parser, Permissions) { {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT, true}, }; - TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}, {}, {}}); + TestUeventdFile(ueventd_file, {{}, {}, sysfs_permissions, permissions, {}, {}, {}}); } TEST(ueventd_parser, FirmwareDirectories) { @@ -148,7 +173,7 @@ firmware_directories /more "/more", }; - TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories, {}, {}}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, firmware_directories, {}, {}}); } TEST(ueventd_parser, ExternalFirmwareHandlers) { @@ -214,7 +239,7 @@ external_firmware_handler /devices/path/firmware/something004.bin radio radio "/ }, }; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers, {}}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, external_firmware_handlers, {}}); } TEST(ueventd_parser, ExternalFirmwareHandlersDuplicate) { @@ -232,7 +257,7 @@ external_firmware_handler devpath root handler_path2 }, }; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers, {}}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, external_firmware_handlers, {}}); } TEST(ueventd_parser, ParallelRestoreconDirs) { @@ -246,7 +271,7 @@ parallel_restorecon_dir /sys/devices "/sys/devices", }; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, parallel_restorecon_dirs}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, parallel_restorecon_dirs}); } TEST(ueventd_parser, UeventSocketRcvbufSize) { @@ -255,7 +280,7 @@ uevent_socket_rcvbuf_size 8k uevent_socket_rcvbuf_size 8M )"; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, false, 8 * 1024 * 1024}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, {}, false, 8 * 1024 * 1024}); } TEST(ueventd_parser, EnabledDisabledLines) { @@ -265,7 +290,7 @@ parallel_restorecon enabled modalias_handling disabled )"; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, false, 0, true}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, {}, false, 0, true}); auto ueventd_file2 = R"( parallel_restorecon enabled @@ -273,7 +298,7 @@ modalias_handling enabled parallel_restorecon disabled )"; - TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, {}, true, 0, false}); + TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, {}, {}, true, 0, false}); } TEST(ueventd_parser, AllTogether) { @@ -286,6 +311,9 @@ firmware_directories /first/ /second /third subsystem test_devname devname uevent_devname +driver d_test_devpath + devname uevent_devpath + /dev/graphics/* 0660 root graphics subsystem test_devpath_no_dirname @@ -303,6 +331,10 @@ subsystem test_devpath_dirname devname uevent_devpath dirname /dev/graphics +driver d_test_devname_dirname + devname uevent_devname + dirname /dev/sound + /dev/*/test 0660 root system /sys/devices/virtual/*/input poll_delay 0660 root input no_fnm_pathname firmware_directories /more @@ -325,6 +357,10 @@ parallel_restorecon_dir /sys/devices {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}}; + auto drivers = std::vector{ + {"d_test_devpath", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"}, + {"d_test_devname_dirname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev/graphics"}}; + auto permissions = std::vector{ {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM, false}, {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS, false}, @@ -356,7 +392,7 @@ parallel_restorecon_dir /sys/devices size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024; TestUeventdFile(ueventd_file, - {subsystems, sysfs_permissions, permissions, firmware_directories, + {subsystems, drivers, sysfs_permissions, permissions, firmware_directories, external_firmware_handlers, parallel_restorecon_dirs, true, uevent_socket_rcvbuf_size, true}); }