summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gki/generic_boot_image_test.cpp82
-rw-r--r--gki/lz4_legacy.cpp18
-rw-r--r--gki/ramdisk_utils.cpp8
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;
}