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
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 83d2b6d..551cf19 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -209,6 +209,8 @@
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 ce67386..b722702 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1180,6 +1180,14 @@
}
}
+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 @@
// 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 255434a..e69b43f 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -246,6 +246,19 @@
}
}
+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()) {
diff --git a/init/util.h b/init/util.h
index 3cdc9f4..7745d77 100644
--- a/init/util.h
+++ b/init/util.h
@@ -55,6 +55,7 @@
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);