Support bootconfig in first stage init and fs_mgr

Androidboot parameters are being moved from the kernel commandline to
bootconfig.
fs_mgr looks for these parameters in properties and falls back to
reading directly from /proc/cmdline. So both of these sources are
updated for bootconfig.
The androidboot parameters from /proc/bootconfig
are added as ro.boot properties, and fs_mgr will fall back to searching
/proc/bootconfig if it is too early.

Test: boot cuttlefish with androidboot.fstab_suffix and
androidboot.hardware in bootconfig and not in cmdline.
Test: atest CtsFsMgrTestCases
Bug: 173815685

Change-Id: Iea36a0da94c26e1aa37d97c576725e0ad77cd3ad
This commit is contained in:
Devin Moore 2020-12-15 16:14:37 -08:00
parent 40839a8469
commit a4ef15bebb
8 changed files with 174 additions and 6 deletions

View file

@ -26,7 +26,7 @@
#include "fs_mgr_priv.h"
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_boot_config(const std::string& cmdline) {
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline) {
static constexpr char quote = '"';
std::vector<std::pair<std::string, std::string>> result;
@ -60,12 +60,50 @@ std::vector<std::pair<std::string, std::string>> fs_mgr_parse_boot_config(const
return result;
}
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_proc_bootconfig(
const std::string& cmdline) {
static constexpr char quote = '"';
std::vector<std::pair<std::string, std::string>> 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 <key> and <key>=
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;

View file

@ -854,7 +854,7 @@ std::set<std::string> GetBootDevices() {
if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
std::set<std::string> 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);
}

View file

@ -22,11 +22,16 @@
#include <utility>
#include <vector>
std::vector<std::pair<std::string, std::string>> fs_mgr_parse_boot_config(const std::string& cmdline);
std::vector<std::pair<std::string, std::string>> 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<std::pair<std::string, std::string>> 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 */

View file

@ -119,10 +119,73 @@ const std::vector<std::pair<std::string, std::string>> 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<std::pair<std::string, std::string>> 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));

View file

@ -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));

View file

@ -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.

View file

@ -246,6 +246,19 @@ void ImportKernelCmdline(const std::function<void(const std::string&, const std:
}
}
void ImportBootconfig(const std::function<void(const std::string&, const std::string&)>& fn) {
std::string bootconfig;
android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
for (const auto& entry : android::base::Split(bootconfig, "\n")) {
std::vector<std::string> 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()) {

View file

@ -55,6 +55,7 @@ Result<uid_t> 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(const std::string&, const std::string&)>&);
void ImportBootconfig(const std::function<void(const std::string&, const std::string&)>&);
bool make_dir(const std::string& path, mode_t mode);
bool is_dir(const char* pathname);
Result<std::string> ExpandProps(const std::string& src);