From 596fac3c6dfd195a4a5bf40bdec7ffb4987383e4 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 6 Jun 2018 16:03:23 -0700 Subject: [PATCH] fs_mgr: fs_mgr_get_boot_config_from_kernel_cmdline deal with quote Spans quoted with " are dealt with atomically, and are stripped from the key/value results when parsing the kernel cmdline. Test: compile, device boot, fs_mgr_unit_test Bug: 109821005 Change-Id: I45f3d7395f34295edefdeaafa4c15c6ee25cc4da --- fs_mgr/fs_mgr_boot_config.cpp | 67 ++++++++++++---- fs_mgr/fs_mgr_priv_boot_config.h | 6 ++ fs_mgr/tests/Android.bp | 36 +++++++++ fs_mgr/tests/fs_mgr_test.cpp | 131 +++++++++++++++++++++++++++++++ 4 files changed, 226 insertions(+), 14 deletions(-) create mode 100644 fs_mgr/tests/Android.bp create mode 100644 fs_mgr/tests/fs_mgr_test.cpp diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp index 9c5d3f3bb..b02fe991c 100644 --- a/fs_mgr/fs_mgr_boot_config.cpp +++ b/fs_mgr/fs_mgr_boot_config.cpp @@ -14,7 +14,10 @@ * limitations under the License. */ +#include +#include #include +#include #include #include @@ -23,28 +26,64 @@ #include "fs_mgr_priv.h" -// 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) { +std::vector> fs_mgr_parse_boot_config(const std::string& cmdline) { + static constexpr char quote = '"'; + + std::vector> result; + size_t base = 0; + while (true) { + // skip quoted spans + auto found = base; + while (((found = cmdline.find_first_of(" \"", found)) != cmdline.npos) && + (cmdline[found] == quote)) { + // unbalanced quote is ok + if ((found = cmdline.find(quote, found + 1)) == cmdline.npos) break; + ++found; + } + std::string piece; + auto source = cmdline.substr(base, found - base); + std::remove_copy(source.begin(), source.end(), + std::back_insert_iterator(piece), quote); + auto equal_sign = piece.find('='); + if (equal_sign == piece.npos) { + if (!piece.empty()) { + // no difference between and = + result.emplace_back(std::move(piece), ""); + } + } else { + result.emplace_back(piece.substr(0, equal_sign), piece.substr(equal_sign + 1)); + } + if (found == cmdline.npos) break; + base = found + 1; + } + + return result; +} + +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); - std::string cmdline; - std::string cmdline_key("androidboot." + key); - if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) { - for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) { - std::vector pieces = android::base::Split(entry, "="); - if (pieces.size() == 2) { - if (pieces[0] == cmdline_key) { - *out_val = pieces[1]; - return true; - } - } + const std::string cmdline_key("androidboot." + android_key); + for (const auto& [key, value] : fs_mgr_parse_boot_config(cmdline)) { + if (key == cmdline_key) { + *out_val = value; + return true; } } + *out_val = ""; return false; } +// 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) { + std::string cmdline; + if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) return false; + return fs_mgr_get_boot_config_from_kernel(cmdline, key, out_val); +} + // Tries to get the boot config value in properties, kernel cmdline and // device tree (in that order). returns 'true' if successfully found, 'false' // otherwise diff --git a/fs_mgr/fs_mgr_priv_boot_config.h b/fs_mgr/fs_mgr_priv_boot_config.h index d98dc02c1..417fb380b 100644 --- a/fs_mgr/fs_mgr_priv_boot_config.h +++ b/fs_mgr/fs_mgr_priv_boot_config.h @@ -19,7 +19,13 @@ #include #include +#include +#include +std::vector> fs_mgr_parse_boot_config(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); diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp new file mode 100644 index 000000000..5497223e0 --- /dev/null +++ b/fs_mgr/tests/Android.bp @@ -0,0 +1,36 @@ +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_test { + name: "fs_mgr_unit_test", + + shared_libs: [ + "libbase", + "liblog", + ], + static_libs: [ + "libfs_mgr", + "libfstab", + ], + + srcs: [ + "fs_mgr_test.cpp", + ], + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], +} diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp new file mode 100644 index 000000000..2e76752c0 --- /dev/null +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "../fs_mgr_priv_boot_config.h" + +namespace { + +const std::string cmdline = + "rcupdate.rcu_expedited=1 rootwait ro " + "init=/init androidboot.bootdevice=1d84000.ufshc " + "androidboot.baseband=sdy androidboot.keymaster=1 skip_initramfs " + "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 " + "dm=\"1 vroot none ro 1,0 10416 verity 1 624684 fec_start 624684\" " + "root=/dev/dm-0 " + "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\" " + "printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 " + "\"string =\"\"string '\" " + "service_locator.enable=1 firmware_class.path=/vendor/firmware " + "cgroup.memory=nokmem lpm_levels.sleep_disabled=1 " + "buildvariant=userdebug console=null " + "terminator=\"truncated"; + +const std::vector> result_space = { + {"rcupdate.rcu_expedited", "1"}, + {"rootwait", ""}, + {"ro", ""}, + {"init", "/init"}, + {"androidboot.bootdevice", "1d84000.ufshc"}, + {"androidboot.baseband", "sdy"}, + {"androidboot.keymaster", "1"}, + {"skip_initramfs", ""}, + {"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"}, + {"dm", "1 vroot none ro 1,0 10416 verity 1 624684 fec_start 624684"}, + {"root", "/dev/dm-0"}, + {"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"}, + {"printk.devkmsg", "on"}, + {"msm_rtb.filter", "0x237"}, + {"ehci-hcd.park", "3"}, + {"string ", "string '"}, + {"service_locator.enable", "1"}, + {"firmware_class.path", "/vendor/firmware"}, + {"cgroup.memory", "nokmem"}, + {"lpm_levels.sleep_disabled", "1"}, + {"buildvariant", "userdebug"}, + {"console", "null"}, + {"terminator", "truncated"}, +}; + +} // namespace + +TEST(fs_mgr, fs_mgr_parse_boot_config) { + EXPECT_EQ(result_space, fs_mgr_parse_boot_config(cmdline)); +} + +TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) { + std::string content; + for (const auto& entry : 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_kernel(cmdline, key, &content)) << " for " << key; + EXPECT_EQ(entry.second, content); + } + EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "vbmeta.avb_versio", &content)); + EXPECT_TRUE(content.empty()) << content; + EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "nospace", &content)); + EXPECT_TRUE(content.empty()) << content; +}