diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp index abece4d7e..75d1e0db6 100644 --- a/fs_mgr/fs_mgr_boot_config.cpp +++ b/fs_mgr/fs_mgr_boot_config.cpp @@ -26,7 +26,7 @@ #include "fs_mgr_priv.h" -std::vector> fs_mgr_parse_boot_config(const std::string& cmdline) { +std::vector> fs_mgr_parse_cmdline(const std::string& cmdline) { static constexpr char quote = '"'; std::vector> result; @@ -60,12 +60,50 @@ std::vector> fs_mgr_parse_boot_config(const return result; } +std::vector> fs_mgr_parse_proc_bootconfig( + const std::string& cmdline) { + static constexpr char quote = '"'; + + std::vector> result; + for (auto& line : android::base::Split(cmdline, "\n")) { + line.erase(std::remove(line.begin(), line.end(), quote), line.end()); + auto equal_sign = line.find('='); + if (equal_sign == line.npos) { + if (!line.empty()) { + // no difference between and = + result.emplace_back(std::move(line), ""); + } + } else { + result.emplace_back(android::base::Trim(line.substr(0, equal_sign)), + android::base::Trim(line.substr(equal_sign + 1))); + } + } + + return result; +} + +bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, + const std::string& android_key, std::string* out_val) { + FS_MGR_CHECK(out_val != nullptr); + + const std::string bootconfig_key("androidboot." + android_key); + for (const auto& [key, value] : fs_mgr_parse_proc_bootconfig(bootconfig)) { + if (key == bootconfig_key) { + *out_val = value; + return true; + } + } + + *out_val = ""; + return false; +} + bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key, std::string* out_val) { FS_MGR_CHECK(out_val != nullptr); const std::string cmdline_key("androidboot." + android_key); - for (const auto& [key, value] : fs_mgr_parse_boot_config(cmdline)) { + for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) { if (key == cmdline_key) { *out_val = value; return true; @@ -76,6 +114,17 @@ bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::s return false; } +// Tries to get the given boot config value from bootconfig. +// Returns true if successfully found, false otherwise. +bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val) { + std::string bootconfig; + if (!android::base::ReadFileToString("/proc/bootconfig", &bootconfig)) return false; + if (!bootconfig.empty() && bootconfig.back() == '\n') { + bootconfig.pop_back(); + } + return fs_mgr_get_boot_config_from_bootconfig(bootconfig, key, out_val); +} + // Tries to get the given boot config value from kernel cmdline. // Returns true if successfully found, false otherwise. bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) { @@ -110,6 +159,11 @@ bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) { return true; } + // next, check if we have the property in bootconfig + if (fs_mgr_get_boot_config_from_bootconfig_source(key, out_val)) { + return true; + } + // finally, fallback to kernel cmdline, properties may not be ready yet if (fs_mgr_get_boot_config_from_kernel_cmdline(key, out_val)) { return true; diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 42459ec9c..8ac3361b7 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -854,7 +854,7 @@ std::set GetBootDevices() { if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) { std::set boot_devices; const std::string cmdline_key = "androidboot.boot_device"; - for (const auto& [key, value] : fs_mgr_parse_boot_config(cmdline)) { + for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) { if (key == cmdline_key) { boot_devices.emplace(value); } diff --git a/fs_mgr/fs_mgr_priv_boot_config.h b/fs_mgr/fs_mgr_priv_boot_config.h index 417fb380b..6a3840131 100644 --- a/fs_mgr/fs_mgr_priv_boot_config.h +++ b/fs_mgr/fs_mgr_priv_boot_config.h @@ -22,11 +22,16 @@ #include #include -std::vector> fs_mgr_parse_boot_config(const std::string& cmdline); +std::vector> fs_mgr_parse_cmdline(const std::string& cmdline); bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& key, std::string* out_val); bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val); bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val); +std::vector> fs_mgr_parse_proc_bootconfig( + const std::string& bootconfig); +bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, const std::string& key, + std::string* out_val); +bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val); #endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */ diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index 46f1c590c..62a8d3b8f 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -119,10 +119,73 @@ const std::vector> result_space = { {"terminator", "truncated"}, }; +const std::string bootconfig = + "androidboot.bootdevice = \" \"1d84000.ufshc\"\n" + "androidboot.baseband = \"sdy\"\n" + "androidboot.keymaster = \"1\"\n" + "androidboot.serialno = \"BLAHBLAHBLAH\"\n" + "androidboot.slot_suffix = \"_a\"\n" + "androidboot.hardware.platform = \"sdw813\"\n" + "androidboot.hardware = \"foo\"\n" + "androidboot.revision = \"EVT1.0\"\n" + "androidboot.bootloader = \"burp-0.1-7521\"\n" + "androidboot.hardware.sku = \"mary\"\n" + "androidboot.hardware.radio.subtype = \"0\"\n" + "androidboot.dtbo_idx = \"2\"\n" + "androidboot.mode = \"normal\"\n" + "androidboot.hardware.ddr = \"1GB,combuchi,LPDDR4X\"\n" + "androidboot.ddr_info = \"combuchiandroidboot.ddr_size=2GB\"\n" + "androidboot.hardware.ufs = \"2GB,combushi\"\n" + "androidboot.boottime = \"0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123\"\n" + "androidboot.ramdump = \"disabled\"\n" + "androidboot.vbmeta.device = \"PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb\"\n" + "androidboot.vbmeta.avb_version = \"1.1\"\n" + "androidboot.vbmeta.device_state = \"unlocked\"\n" + "androidboot.vbmeta.hash_alg = \"sha256\"\n" + "androidboot.vbmeta.size = \"5248\"\n" + "androidboot.vbmeta.digest = \"" + "ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860\"\n" + "androidboot.vbmeta.invalidate_on_error = \"yes\"\n" + "androidboot.veritymode = \"enforcing\"\n" + "androidboot.verifiedbootstate = \"orange\"\n" + "androidboot.space = \"sha256 5248 androidboot.nospace = nope\"\n"; + +const std::vector> bootconfig_result_space = { + {"androidboot.bootdevice", "1d84000.ufshc"}, + {"androidboot.baseband", "sdy"}, + {"androidboot.keymaster", "1"}, + {"androidboot.serialno", "BLAHBLAHBLAH"}, + {"androidboot.slot_suffix", "_a"}, + {"androidboot.hardware.platform", "sdw813"}, + {"androidboot.hardware", "foo"}, + {"androidboot.revision", "EVT1.0"}, + {"androidboot.bootloader", "burp-0.1-7521"}, + {"androidboot.hardware.sku", "mary"}, + {"androidboot.hardware.radio.subtype", "0"}, + {"androidboot.dtbo_idx", "2"}, + {"androidboot.mode", "normal"}, + {"androidboot.hardware.ddr", "1GB,combuchi,LPDDR4X"}, + {"androidboot.ddr_info", "combuchiandroidboot.ddr_size=2GB"}, + {"androidboot.hardware.ufs", "2GB,combushi"}, + {"androidboot.boottime", "0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123"}, + {"androidboot.ramdump", "disabled"}, + {"androidboot.vbmeta.device", "PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb"}, + {"androidboot.vbmeta.avb_version", "1.1"}, + {"androidboot.vbmeta.device_state", "unlocked"}, + {"androidboot.vbmeta.hash_alg", "sha256"}, + {"androidboot.vbmeta.size", "5248"}, + {"androidboot.vbmeta.digest", + "ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860"}, + {"androidboot.vbmeta.invalidate_on_error", "yes"}, + {"androidboot.veritymode", "enforcing"}, + {"androidboot.verifiedbootstate", "orange"}, + {"androidboot.space", "sha256 5248 androidboot.nospace = nope"}, +}; + } // namespace -TEST(fs_mgr, fs_mgr_parse_boot_config) { - EXPECT_EQ(result_space, fs_mgr_parse_boot_config(cmdline)); +TEST(fs_mgr, fs_mgr_parse_cmdline) { + EXPECT_EQ(result_space, fs_mgr_parse_cmdline(cmdline)); } TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) { @@ -140,6 +203,27 @@ TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) { EXPECT_TRUE(content.empty()) << content; } +TEST(fs_mgr, fs_mgr_parse_bootconfig) { + EXPECT_EQ(bootconfig_result_space, fs_mgr_parse_proc_bootconfig(bootconfig)); +} + +TEST(fs_mgr, fs_mgr_get_boot_config_from_bootconfig) { + std::string content; + for (const auto& entry : bootconfig_result_space) { + static constexpr char androidboot[] = "androidboot."; + if (!android::base::StartsWith(entry.first, androidboot)) continue; + auto key = entry.first.substr(strlen(androidboot)); + EXPECT_TRUE(fs_mgr_get_boot_config_from_bootconfig(bootconfig, key, &content)) + << " for " << key; + EXPECT_EQ(entry.second, content); + } + + EXPECT_FALSE(fs_mgr_get_boot_config_from_bootconfig(bootconfig, "vbmeta.avb_versio", &content)); + EXPECT_TRUE(content.empty()) << content; + EXPECT_FALSE(fs_mgr_get_boot_config_from_bootconfig(bootconfig, "nospace", &content)); + EXPECT_TRUE(content.empty()) << content; +} + TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) { Fstab fstab; ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &fstab)); diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index 83d2b6d37..551cf1951 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -209,6 +209,8 @@ int FirstStageMain(int argc, char** argv) { CHECKCALL(chmod("/proc/cmdline", 0440)); std::string cmdline; android::base::ReadFileToString("/proc/cmdline", &cmdline); + // Don't expose the raw bootconfig to unprivileged processes. + chmod("/proc/bootconfig", 0440); gid_t groups[] = {AID_READPROC}; CHECKCALL(setgroups(arraysize(groups), groups)); CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL)); diff --git a/init/property_service.cpp b/init/property_service.cpp index ce6738634..b7227020d 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -1180,6 +1180,14 @@ static void ProcessKernelCmdline() { } } +static void ProcessBootconfig() { + ImportBootconfig([&](const std::string& key, const std::string& value) { + if (StartsWith(key, "androidboot.")) { + InitPropertySet("ro.boot." + key.substr(12), value); + } + }); +} + void PropertyInit() { selinux_callback cb; cb.func_audit = PropertyAuditCallback; @@ -1198,6 +1206,7 @@ void PropertyInit() { // properties set in DT always have priority over the command-line ones. ProcessKernelDt(); ProcessKernelCmdline(); + ProcessBootconfig(); // Propagate the kernel variables to internal variables // used by init as well as the current required properties. diff --git a/init/util.cpp b/init/util.cpp index 255434a1b..e69b43f8c 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -246,6 +246,19 @@ void ImportKernelCmdline(const std::function& fn) { + std::string bootconfig; + android::base::ReadFileToString("/proc/bootconfig", &bootconfig); + + for (const auto& entry : android::base::Split(bootconfig, "\n")) { + std::vector pieces = android::base::Split(entry, "="); + if (pieces.size() == 2) { + pieces[1].erase(std::remove(pieces[1].begin(), pieces[1].end(), '"'), pieces[1].end()); + fn(android::base::Trim(pieces[0]), android::base::Trim(pieces[1])); + } + } +} + bool make_dir(const std::string& path, mode_t mode) { std::string secontext; if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) { diff --git a/init/util.h b/init/util.h index 3cdc9f408..7745d775a 100644 --- a/init/util.h +++ b/init/util.h @@ -55,6 +55,7 @@ Result DecodeUid(const std::string& name); bool mkdir_recursive(const std::string& pathname, mode_t mode); int wait_for_file(const char *filename, std::chrono::nanoseconds timeout); void ImportKernelCmdline(const std::function&); +void ImportBootconfig(const std::function&); bool make_dir(const std::string& path, mode_t mode); bool is_dir(const char* pathname); Result ExpandProps(const std::string& src);