diff options
-rw-r--r-- | gki/generic_boot_image_test.cpp | 82 | ||||
-rw-r--r-- | gki/lz4_legacy.cpp | 18 | ||||
-rw-r--r-- | gki/ramdisk_utils.cpp | 8 |
3 files changed, 85 insertions, 23 deletions
diff --git a/gki/generic_boot_image_test.cpp b/gki/generic_boot_image_test.cpp index 3fd1e853..691c0929 100644 --- a/gki/generic_boot_image_test.cpp +++ b/gki/generic_boot_image_test.cpp @@ -17,6 +17,7 @@ #include <filesystem> #include <android-base/properties.h> +#include <android-base/strings.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <kver/kernel_release.h> @@ -64,6 +65,43 @@ TEST_F(GenericBootImageTest, KernelReleaseFormat) { << "\nExample: 5.4.42-android12-0-something"; } +std::set<std::string> GetRequirementBySdkLevel(uint32_t target_sdk_level) { + // Files which must be present in generic ramdisk. This list acts as a lower + // bound for device's ramdisk. + static const std::map<uint32_t, std::set<std::string>> required_by_level = { + {0, {"init", "system/etc/ramdisk/build.prop"}}, // or some other number? + { + __ANDROID_API_T__, + {"system/bin/snapuserd", "system/etc/init/snapuserd.rc"}, + }}; + std::set<std::string> res; + for (const auto& [level, requirements] : required_by_level) { + if (level > target_sdk_level) { + break; + } + res.insert(requirements.begin(), requirements.end()); + } + return res; +} + +std::set<std::string> GetAllowListBySdkLevel(uint32_t target_sdk_level) { + // Files that are allowed in generic ramdisk(but not necessarily required) + // This list acts as an upper bound for what the device's ramdisk can possibly + // contain. + static const std::map<uint32_t, std::set<std::string>> allow_by_level = {{ + __ANDROID_API_T__, + {"system/bin/snapuserd_ramdisk"}, + }}; + auto res = GetRequirementBySdkLevel(target_sdk_level); + for (const auto& [level, requirements] : allow_by_level) { + if (level > target_sdk_level) { + break; + } + res.insert(requirements.begin(), requirements.end()); + } + return res; +} + TEST_F(GenericBootImageTest, GenericRamdisk) { // On "GKI 2.0" with 5.10+ kernels, VTS runs once with the device kernel, // so this test is meaningful. @@ -71,6 +109,7 @@ TEST_F(GenericBootImageTest, GenericRamdisk) { GTEST_SKIP() << "Exempt generic ramdisk test on kernel " << runtime_info->kernelVersion() << ". Only required on 5.10+."; + return; } using std::filesystem::recursive_directory_iterator; @@ -97,21 +136,23 @@ TEST_F(GenericBootImageTest, GenericRamdisk) { GTEST_SKIP() << "Exempt generic ramdisk test on upgrading device that " << "launched before Android 13 and is now using an Android " << "13+ kernel."; + return; } } else { boot_path = "/dev/block/by-name/boot" + slot_suffix; } - if (0 != access(boot_path.c_str(), F_OK)) { + if (0 != access(boot_path.c_str(), R_OK)) { int saved_errno = errno; FAIL() << "Can't access " << boot_path << ": " << strerror(saved_errno); + return; } - auto extracted_ramdisk = android::ExtractRamdiskToDirectory(boot_path); + const auto extracted_ramdisk = android::ExtractRamdiskToDirectory(boot_path); ASSERT_TRUE(extracted_ramdisk.ok()) - << "Failed to find the block device: " << boot_path; + << "Failed to extract ramdisk: " << extracted_ramdisk.error(); std::set<std::string> actual_files; - std::filesystem::path extracted_ramdisk_path((*extracted_ramdisk)->path); + const std::filesystem::path extracted_ramdisk_path((*extracted_ramdisk)->path); for (auto& p : recursive_directory_iterator(extracted_ramdisk_path)) { if (p.is_directory()) continue; EXPECT_TRUE(p.is_regular_file()) @@ -120,24 +161,27 @@ TEST_F(GenericBootImageTest, GenericRamdisk) { actual_files.insert(rel_path.string()); } - std::set<std::string> generic_ramdisk_allowlist{ - "init", - "system/bin/snapuserd", - "system/etc/ramdisk/build.prop", - }; - if (GetBoolProperty("ro.debuggable", false)) { - EXPECT_THAT(actual_files, IsSupersetOf(generic_ramdisk_allowlist)) - << "Missing files required by non-debuggable generic ramdisk."; - std::set<std::string> debuggable_allowlist{ + const auto sdk_level = + android::base::GetIntProperty("ro.bootimage.build.version.sdk", 0); + const std::set<std::string> generic_ramdisk_required_list = + GetRequirementBySdkLevel(sdk_level); + std::set<std::string> generic_ramdisk_allow_list = + GetAllowListBySdkLevel(sdk_level); + + const bool is_debuggable = GetBoolProperty("ro.debuggable", false); + if (is_debuggable) { + const std::set<std::string> debuggable_allowlist{ "adb_debug.prop", "force_debuggable", "userdebug_plat_sepolicy.cil", }; - generic_ramdisk_allowlist.insert(debuggable_allowlist.begin(), - debuggable_allowlist.end()); - EXPECT_THAT(generic_ramdisk_allowlist, IsSupersetOf(actual_files)) - << "Contains files disallowed by debuggable generic ramdisk"; - } else { - EXPECT_EQ(actual_files, generic_ramdisk_allowlist); + generic_ramdisk_allow_list.insert(debuggable_allowlist.begin(), + debuggable_allowlist.end()); } + EXPECT_THAT(actual_files, IsSupersetOf(generic_ramdisk_required_list)) + << "Missing files required by " << (is_debuggable ? "debuggable " : "") + << "generic ramdisk"; + EXPECT_THAT(generic_ramdisk_allow_list, IsSupersetOf(actual_files)) + << "Contains files disallowed by " << (is_debuggable ? "debuggable " : "") + << "generic ramdisk"; } diff --git a/gki/lz4_legacy.cpp b/gki/lz4_legacy.cpp index 55d0a9b6..423687c7 100644 --- a/gki/lz4_legacy.cpp +++ b/gki/lz4_legacy.cpp @@ -19,6 +19,7 @@ #include <fcntl.h> #include <sys/stat.h> +#include <iostream> #include <vector> #include <android-base/file.h> @@ -41,13 +42,24 @@ android::base::Result<void> Lz4DecompressLegacy(const char* input, constexpr uint32_t lz4_legacy_magic = 0x184C2102; constexpr auto lz4_legacy_block_size = 8_MiB; + struct stat st_buf {}; + if (stat(input, &st_buf) != 0) { + return ErrnoError() << "stat(" << input << ")"; + } + unique_fd ifd(TEMP_FAILURE_RETRY(open(input, O_RDONLY | O_CLOEXEC))); + if (!ifd.ok()) { + return ErrnoError() << "open(" << input << ", O_RDONLY)"; + } unique_fd ofd(TEMP_FAILURE_RETRY( open(output, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0640))); + if (!ofd.ok()) { + return ErrnoError() << "open(" << output << ", O_WRONLY | O_CREAT)"; + } - uint32_t magic; + uint32_t magic{}; if (!ReadFully(ifd, &magic, sizeof(magic))) { - return ErrnoError() << "read magic"; + return ErrnoError() << "read lz4 magic " << input; } // Android is little-endian. No need to convert magic. if (magic != lz4_legacy_magic) { @@ -59,7 +71,7 @@ android::base::Result<void> Lz4DecompressLegacy(const char* input, std::vector<char> obuf(lz4_legacy_block_size); while (true) { - uint32_t block_size; + uint32_t block_size{}; ssize_t read_bytes = TEMP_FAILURE_RETRY(read(ifd.get(), &block_size, sizeof(block_size))); if (read_bytes == 0) break; diff --git a/gki/ramdisk_utils.cpp b/gki/ramdisk_utils.cpp index a6ec24aa..a133edf8 100644 --- a/gki/ramdisk_utils.cpp +++ b/gki/ramdisk_utils.cpp @@ -18,6 +18,7 @@ #include <android-base/file.h> #include <android-base/result.h> #include <bootimg.h> +#include <iostream> #include "cpio.h" #include "lz4_legacy.h" @@ -37,7 +38,7 @@ android::base::Result<std::unique_ptr<TemporaryFile>> ExtractRamdiskRaw( android::base::unique_fd bootimg( TEMP_FAILURE_RETRY(open(boot_path.data(), O_RDONLY))); if (!bootimg.ok()) return ErrnoError() << "open(" << boot_path << ")"; - boot_img_hdr_v3 hdr; + boot_img_hdr_v3 hdr{}; if (!ReadFullyAtOffset(bootimg.get(), &hdr, sizeof(hdr), 0)) return ErrnoError() << "read header"; if (0 != memcmp(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) @@ -45,6 +46,10 @@ android::base::Result<std::unique_ptr<TemporaryFile>> ExtractRamdiskRaw( if (hdr.header_version < 3) return Error() << "Unsupported header version V" << hdr.header_version; + if (hdr.ramdisk_size <= 0) { + return Error() << boot_path + << " contains a valid bootimg header but no ramdisk"; + } // See bootimg.h auto kernel_size_bytes = (hdr.kernel_size + 4096 - 1) / 4096 * 4096; @@ -58,6 +63,7 @@ android::base::Result<std::unique_ptr<TemporaryFile>> ExtractRamdiskRaw( auto ramdisk_content_file = std::make_unique<TemporaryFile>(); if (!WriteStringToFd(ramdisk_content, ramdisk_content_file->fd)) return ErrnoError() << "write ramdisk section to file"; + fsync(ramdisk_content_file->fd); return ramdisk_content_file; } |