fs_mgr: add a generic fs_mgr_get_boot_config internal API

depending on when fs_mgr is trying to read the configuration passed into
the kernel commandline, it may be able to read it successfully.
Specially in the case when init has not initialized properties.

This change adds a new fs_mgr_get_boot_config() API to be used by all
fs_mgr code in order to get filesystem parameters specified in kernel
command line or device tree. This way the fs_mgr code doesn't have to
handle the "early" cases separately anywhere.

Test:
Tested angler boot with both /system and /vendor mounted in init
first stage.
Tested sailfish to make sure /vendor can be continued to be
mounted early without verity

Change-Id: I9a44cdfc32681f714c5d73ae55c3deda95c02545
This commit is contained in:
Sandeep Patil 2017-02-16 19:15:29 -08:00
parent e9da79bd44
commit 9de748f745
7 changed files with 120 additions and 105 deletions

View File

@ -25,7 +25,8 @@ LOCAL_SRC_FILES:= \
fs_mgr_slotselect.cpp \
fs_mgr_verity.cpp \
fs_mgr_avb.cpp \
fs_mgr_avb_ops.cpp
fs_mgr_avb_ops.cpp \
fs_mgr_boot_config.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
system/vold \

View File

@ -441,18 +441,23 @@ static bool get_hashtree_descriptor(const std::string& partition_name,
static bool init_is_avb_used() {
// When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg,
// size, digest} in kernel cmdline. They will then be imported by init
// process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
// size, digest} in kernel cmdline or in device tree. They will then be
// imported by init process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
//
// In case of early mount, init properties are not initialized, so we also
// ensure we look into kernel command line and device tree if the property is
// not found
//
// Checks hash_alg as an indicator for whether AVB is used.
// We don't have to parse and check all of them here. The check will
// be done in fs_mgr_load_vbmeta_images() and FS_MGR_SETUP_AVB_FAIL will
// be returned when there is an error.
std::string hash_alg = android::base::GetProperty("ro.boot.vbmeta.hash_alg", "");
if (hash_alg == "sha256" || hash_alg == "sha512") {
return true;
std::string hash_alg;
if (fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg) == 0) {
if (hash_alg == "sha256" || hash_alg == "sha512") {
return true;
}
}
return false;
@ -482,10 +487,11 @@ int fs_mgr_load_vbmeta_images(struct fstab* fstab) {
// Sets requested_partitions to nullptr as it's to copy the contents
// of HASH partitions into fs_mgr_avb_verify_data, which is not required as
// fs_mgr only deals with HASHTREE partitions.
const char* requested_partitions[] = {nullptr};
const char* ab_suffix = android::base::GetProperty("ro.boot.slot_suffix", "").c_str();
const char *requested_partitions[] = {nullptr};
std::string ab_suffix;
fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
AvbSlotVerifyResult verify_result =
avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix,
avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix.c_str(),
fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data);
// Only allow two verify results:

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2017 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 <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/properties.h>
#include "fs_mgr_priv.h"
// Tries to get the boot config value in properties, kernel cmdline and
// device tree (in that order). returns 'true' if successfully found, 'false'
// otherwise
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
FS_MGR_CHECK(out_val != nullptr);
// first check if we have "ro.boot" property already
*out_val = android::base::GetProperty("ro.boot." + key, "");
if (!out_val->empty()) {
return true;
}
// fallback to kernel cmdline, properties may not be ready yet
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<std::string> pieces = android::base::Split(entry, "=");
if (pieces.size() == 2) {
if (pieces[0] == cmdline_key) {
*out_val = pieces[1];
return true;
}
}
}
}
// lastly, check the device tree
static const std::string android_dt_dir("/proc/device-tree/firmware/android");
std::string file_name = android_dt_dir + "/compatible";
std::string dt_value;
if (android::base::ReadFileToString(file_name, &dt_value)) {
if (dt_value != "android,firmware") {
LERROR << "Error finding compatible android DT node";
return false;
}
file_name = android_dt_dir + "/" + key;
// DT entries terminate with '\0' but so do the properties
if (android::base::ReadFileToString(file_name, out_val)) {
return true;
}
LERROR << "Error finding '" << key << "' in device tree";
}
return false;
}

View File

@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <fs_mgr.h>
#include "fs_mgr_priv_boot_config.h"
/* The CHECK() in logging.h will use program invocation name as the tag.
* Thus, the log will have prefix "init: " when libfs_mgr is statically

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2017 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.
*/
#ifndef __CORE_FS_MGR_PRIV_BOOTCONFIG_H
#define __CORE_FS_MGR_PRIV_BOOTCONFIG_H
#include <sys/cdefs.h>
#include <string>
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);
#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */

View File

@ -14,118 +14,31 @@
* limitations under the License.
*/
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
// finds slot_suffix in androidboot.slot_suffix kernel command line argument
// or in the device tree node at /firmware/android/slot_suffix property
static int get_active_slot_suffix_from_kernel(char *out_suffix,
size_t suffix_len)
{
std::string cmdline;
if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
std::vector<std::string> pieces = android::base::Split(entry, "=");
if (pieces.size() == 2) {
if (pieces[0] == "androidboot.slot_suffix") {
strncpy(out_suffix, pieces[1].c_str(), suffix_len);
return 0;
}
}
}
}
// if we can't find slot_suffix in cmdline, check the DT
static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
std::string file_name = android::base::StringPrintf("%s/compatible", android_dt_dir);
std::string dt_value;
if (android::base::ReadFileToString(file_name, &dt_value)) {
if (!dt_value.compare("android,firmware")) {
LERROR << "Error finding compatible android DT node";
return -1;
}
file_name = android::base::StringPrintf("%s/%s", android_dt_dir, "slot_suffix");
if (!android::base::ReadFileToString(file_name, &dt_value)) {
LERROR << "Error finding slot_suffix in device tree";
return -1;
}
// DT entries have a terminating '\0', so 'suffix_len' is safe.
strncpy(out_suffix, dt_value.c_str(), suffix_len);
return 0;
}
// slot_suffix missing in kernel cmdline or device tree
return -1;
}
// Gets slot_suffix from either the kernel cmdline / device tree. Sets
// |out_suffix| on success and returns 0. Returns -1 if slot_suffix could not
// be determined.
static int get_active_slot_suffix(char *out_suffix, size_t suffix_len)
{
char propbuf[PROPERTY_VALUE_MAX];
// Get the suffix from the kernel commandline (note that we don't
// allow the empty suffix). On bootloaders natively supporting A/B
// we'll hit this path every time so don't bother logging it.
property_get("ro.boot.slot_suffix", propbuf, "");
if (propbuf[0] != '\0') {
strncpy(out_suffix, propbuf, suffix_len);
return 0;
}
// if the property is not set, we are probably being invoked early during
// boot. Try to find the slotsuffix ourselves in the kernel command line
// or the device tree
if (get_active_slot_suffix_from_kernel(out_suffix, suffix_len) == 0) {
LINFO << "Using slot suffix '" << out_suffix << "' from kernel";
return 0;
}
LERROR << "Error determining slot_suffix";
return -1;
}
// Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error.
int fs_mgr_update_for_slotselect(struct fstab *fstab)
{
int n;
char suffix[PROPERTY_VALUE_MAX];
int got_suffix = 0;
std::string suffix;
for (n = 0; n < fstab->num_entries; n++) {
if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
char *tmp;
if (!got_suffix) {
memset(suffix, '\0', sizeof(suffix));
if (get_active_slot_suffix(suffix, sizeof(suffix) - 1) != 0) {
if (!fs_mgr_get_boot_config("slot_suffix", &suffix)) {
return -1;
}
got_suffix = 1;
}
if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device,
suffix) > 0) {
suffix.c_str()) > 0) {
free(fstab->recs[n].blk_device);
fstab->recs[n].blk_device = tmp;
} else {

View File

@ -657,7 +657,6 @@ static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
static int load_verity_state(struct fstab_rec *fstab, int *mode)
{
char propbuf[PROPERTY_VALUE_MAX];
int match = 0;
off64_t offset = 0;
@ -665,10 +664,9 @@ static int load_verity_state(struct fstab_rec *fstab, int *mode)
*mode = VERITY_MODE_EIO;
/* use the kernel parameter if set */
property_get("ro.boot.veritymode", propbuf, "");
if (*propbuf != '\0') {
if (!strcmp(propbuf, "enforcing")) {
std::string veritymode;
if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
if (veritymode.compare("enforcing")) {
*mode = VERITY_MODE_DEFAULT;
}
return 0;