From 56f9ada93d83dcd66322635138e334e25bb5e1bd Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Tue, 14 Feb 2017 14:00:14 -0800 Subject: [PATCH 1/8] fs_mgr: add fs_mgr_do_mount_one() API This is to be used in early mount case where we will have a fully prepared fstab_rec. fs_mgr_do_mount() does a lot more checks and spends time preparing verity / avb devices before it does the actual mount. b/33254008 Test: Boot sailfish Change-Id: I4481b5af8d900c8b7e3355b7513c325d8f2ecff2 Signed-off-by: Sandeep Patil --- fs_mgr/fs_mgr.cpp | 18 ++++++++++++++++++ fs_mgr/include/fs_mgr.h | 1 + 2 files changed, 19 insertions(+) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 176807801..cc607d3f9 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -880,6 +880,24 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode) } } +/* wrapper to __mount() and expects a fully prepared fstab_rec, + * unlike fs_mgr_do_mount which does more things with avb / verity + * etc. + */ +int fs_mgr_do_mount_one(struct fstab_rec *rec) +{ + if (!rec) { + return FS_MGR_DOMNT_FAILED; + } + + int ret = __mount(rec->blk_device, rec->mount_point, rec); + if (ret) { + ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED; + } + + return ret; +} + /* If tmp_mount_point is non-null, mount the filesystem there. This is for the * tmp mount we do to check the user password * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index a9deed948..d6d94896e 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -103,6 +103,7 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode); int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device, char *tmp_mount_point); +int fs_mgr_do_mount_one(struct fstab_rec *rec); int fs_mgr_do_tmpfs_mount(char *n_name); int fs_mgr_unmount_all(struct fstab *fstab); int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, From 971a460c5b573b0e22780579daed242f4879626d Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Wed, 15 Feb 2017 13:37:52 -0800 Subject: [PATCH 2/8] init: refactor to allow successive device_init calls device_init opens the uevent socket and sehandle when called. For early_mount however, depending on the fs_mgr flags we may call this in order to run coldboot for device mapper, dm-verity devices etc. So the change makes sure we don't try to re-open the uevent socket, file context handle and selinux status on successive calls to device_init from within the same process. b/27805372 Test: Boot saifish successfully Change-Id: Ifa0e665403211684183efb9be66e4e8d0d86a206 Signed-off-by: Sandeep Patil --- init/devices.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/init/devices.cpp b/init/devices.cpp index b3b808b89..5f54ff8fd 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -999,15 +999,20 @@ static coldboot_action_t coldboot(const char *path, coldboot_callback fn) } void device_init(const char* path, coldboot_callback fn) { - sehandle = selinux_android_file_context_handle(); - selinux_status_open(true); - - /* is 256K enough? udev uses 16MB! */ - device_fd.reset(uevent_open_socket(256*1024, true)); - if (device_fd == -1) { - return; + if (!sehandle) { + sehandle = selinux_android_file_context_handle(); + } + // open uevent socket and selinux status only if it hasn't been + // done before + if (device_fd == -1) { + /* is 256K enough? udev uses 16MB! */ + device_fd.reset(uevent_open_socket(256 * 1024, true)); + if (device_fd == -1) { + return; + } + fcntl(device_fd, F_SETFL, O_NONBLOCK); + selinux_status_open(true); } - fcntl(device_fd, F_SETFL, O_NONBLOCK); if (access(COLDBOOT_DONE, F_OK) == 0) { LOG(VERBOSE) << "Skipping coldboot, already done!"; @@ -1040,6 +1045,7 @@ void device_init(const char* path, coldboot_callback fn) { void device_close() { destroy_platform_devices(); device_fd.reset(); + selinux_status_close(); } int get_device_fd() { From d2462570b8dffd2e83dfb9c6e60f8f39697659b5 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Wed, 15 Feb 2017 14:24:39 -0800 Subject: [PATCH 3/8] fs_mgr: fix the fs_mgr_setup_verity param name The 'verify_dev' parameter for fs_mgr_setup_verity is confusing, since it doesn't necessarily control the "verification" part of the function. Instead, it merely allows the caller to skip the wait_for_dm_verity_device part of the function. So, rename that parameter for what it is. b/27805372 Test: Boot sailfish Change-Id: I024e02fd728f5cd5bb333d9c3b512861731fa215 Signed-off-by: Sandeep Patil --- fs_mgr/fs_mgr.cpp | 2 ++ fs_mgr/fs_mgr_verity.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index cc607d3f9..28d33973f 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -661,6 +661,8 @@ static int handle_encryptable(const struct fstab_rec* rec) } } +// TODO: add ueventd notifiers if they don't exist. +// This is just doing a wait_for_device for maximum of 1s int fs_mgr_test_access(const char *device) { int tries = 25; while (tries--) { diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp index 1ec454072..e82913999 100644 --- a/fs_mgr/fs_mgr_verity.cpp +++ b/fs_mgr/fs_mgr_verity.cpp @@ -859,7 +859,10 @@ static void update_verity_table_blk_device(char *blk_device, char **table) *table = strdup(result.c_str()); } -int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev) +// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for +// mount. The 'wait_for_verity_dev' parameter makes this function wait for the +// verity device to get created before return +int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev) { int retval = FS_MGR_SETUP_VERITY_FAIL; int fd = -1; @@ -1026,7 +1029,7 @@ loaded: } // make sure we've set everything up properly - if (verify_dev && fs_mgr_test_access(fstab->blk_device) < 0) { + if (wait_for_verity_dev && fs_mgr_test_access(fstab->blk_device) < 0) { goto out; } From 4129f20aafe07431a5950271cf7b9014bee53550 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Wed, 15 Feb 2017 15:36:25 -0800 Subject: [PATCH 4/8] fs_mgr: make fs_mgr_setup_verity public API Consequently this removes the 'early' version of the exact same API. This is to be used by early mount code where we need to do 1. setup verity 2. create verity device 3. mount partition as separate steps since that happens during init first stage. b/27805372 Test: Boot sailfish successfully Change-Id: I01abecfdfa210d3e240a291ddcb3d2e9ed39ede6 Signed-off-by: Sandeep Patil --- fs_mgr/fs_mgr.cpp | 20 -------------------- fs_mgr/fs_mgr_priv_verity.h | 27 --------------------------- fs_mgr/fs_mgr_verity.cpp | 1 - fs_mgr/include/fs_mgr.h | 8 ++++---- 4 files changed, 4 insertions(+), 52 deletions(-) delete mode 100644 fs_mgr/fs_mgr_priv_verity.h diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 28d33973f..25c41b96e 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -48,7 +48,6 @@ #include "fs_mgr_priv.h" #include "fs_mgr_priv_avb.h" -#include "fs_mgr_priv_verity.h" #define KEY_LOC_PROP "ro.crypto.keyfile.userdata" #define KEY_IN_FOOTER "footer" @@ -1191,22 +1190,3 @@ int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_dev return 0; } - -int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec) -{ - if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) { - int rc = fs_mgr_setup_verity(fstab_rec, false); - if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { - LINFO << "Verity disabled"; - return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY; - } else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) { - return FS_MGR_EARLY_SETUP_VERITY_SUCCESS; - } else { - return FS_MGR_EARLY_SETUP_VERITY_FAIL; - } - } else if (device_is_secure()) { - LERROR << "Verity must be enabled for early mounted partitions on secured devices"; - return FS_MGR_EARLY_SETUP_VERITY_FAIL; - } - return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY; -} diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h deleted file mode 100644 index 1a6d215cb..000000000 --- a/fs_mgr/fs_mgr_priv_verity.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2013 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 - -#define FS_MGR_SETUP_VERITY_DISABLED (-2) -#define FS_MGR_SETUP_VERITY_FAIL (-1) -#define FS_MGR_SETUP_VERITY_SUCCESS 0 - -__BEGIN_DECLS - -int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev); - -__END_DECLS diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp index e82913999..d72ac73de 100644 --- a/fs_mgr/fs_mgr_verity.cpp +++ b/fs_mgr/fs_mgr_verity.cpp @@ -45,7 +45,6 @@ #include "fs_mgr.h" #include "fs_mgr_priv.h" #include "fs_mgr_priv_dm_ioctl.h" -#include "fs_mgr_priv_verity.h" #define FSTAB_PREFIX "/fstab." diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index d6d94896e..7b389cd1c 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -132,10 +132,10 @@ int fs_mgr_swapon_all(struct fstab *fstab); int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer); -#define FS_MGR_EARLY_SETUP_VERITY_NO_VERITY -2 -#define FS_MGR_EARLY_SETUP_VERITY_FAIL -1 -#define FS_MGR_EARLY_SETUP_VERITY_SUCCESS 0 -int fs_mgr_early_setup_verity(struct fstab_rec *fstab); +#define FS_MGR_SETUP_VERITY_DISABLED (-2) +#define FS_MGR_SETUP_VERITY_FAIL (-1) +#define FS_MGR_SETUP_VERITY_SUCCESS 0 +int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev); #ifdef __cplusplus } From 0a3e36fbb19315de6208560e239dbc7cccbba214 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Wed, 15 Feb 2017 15:45:01 -0800 Subject: [PATCH 5/8] init: early_mount: add support to mount verity enabled partitions early support mounting partitions early regardless of their "verified" status. uses the newly exported fs_mgr APIs to split verity setup and mount operations. b/27805372 Test: Angler: - Early mount /vendor without dm-verity Sailfish: - Early mount /vendor without dm-verity - Early mount /vendor with dm-verity TODO: add support for metadata partition used in angler to load dm-verity data Change-Id: Ie2768d4d895c19d045293c573773ee7bb03fff99 Signed-off-by: Sandeep Patil --- init/init.cpp | 72 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index 7f7eb2f00..702186cfa 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -736,6 +736,38 @@ static std::string import_dt_fstab() { return fstab; } +static bool early_mount_one(struct fstab_rec* rec) { + if (rec && fs_mgr_is_verified(rec)) { + // setup verity and create the dm-XX block device + // needed to mount this partition + int ret = fs_mgr_setup_verity(rec, false); + if (ret == FS_MGR_SETUP_VERITY_FAIL) { + PLOG(ERROR) << "early_mount: Failed to setup verity for '" << rec->mount_point << "'"; + return false; + } + + // The exact block device name is added as a mount source by + // fs_mgr_setup_verity() in ->blk_device as "/dev/block/dm-XX" + // We create that device by running coldboot on /sys/block/dm-XX + std::string dm_device(basename(rec->blk_device)); + std::string syspath = StringPrintf("/sys/block/%s", dm_device.c_str()); + device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t { + if (uevent->device_name && !strcmp(dm_device.c_str(), uevent->device_name)) { + LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device; + return COLDBOOT_STOP; + } + return COLDBOOT_CONTINUE; + }); + } + + if (rec && fs_mgr_do_mount_one(rec)) { + PLOG(ERROR) << "early_mount: Failed to mount '" << rec->mount_point << "'"; + return false; + } + + return true; +} + /* Early mount vendor and ODM partitions. The fstab is read from device-tree. */ static bool early_mount() { std::string fstab = import_dt_fstab(); @@ -802,9 +834,7 @@ static bool early_mount() { // wait twice for A/B-ed partitions count_odm++; - if (!is_ab) { - found_odm = true; - } else if (count_odm == 2) { + if (!is_ab || count_odm == 2) { found_odm = true; } @@ -813,9 +843,7 @@ static bool early_mount() { LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition"; count_system++; - if (!is_ab) { - found_system = true; - } else if (count_system == 2) { + if (!is_ab || count_system == 2) { found_system = true; } @@ -823,9 +851,7 @@ static bool early_mount() { } else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) { LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition"; count_vendor++; - if (!is_ab) { - found_vendor = true; - } else if (count_vendor == 2) { + if (!is_ab || count_vendor == 2) { found_vendor = true; } @@ -848,24 +874,24 @@ static bool early_mount() { return ret; }); - // TODO: add support to mount partitions w/ verity - - int ret = 0; - if (odm_rec && - (ret = fs_mgr_do_mount(tab.get(), odm_rec->mount_point, odm_rec->blk_device, NULL))) { - PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting odm"; - return false; + // check for verified partitions + bool need_verity = ((odm_rec && fs_mgr_is_verified(odm_rec)) || + (system_rec && fs_mgr_is_verified(system_rec)) || + (vendor_rec && fs_mgr_is_verified(vendor_rec))); + if (need_verity) { + // create /dev/device mapper + device_init("/sys/devices/virtual/misc/device-mapper", + [&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; }); } - if (vendor_rec && - (ret = fs_mgr_do_mount(tab.get(), vendor_rec->mount_point, vendor_rec->blk_device, NULL))) { - PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting vendor"; - return false; - } + bool success = true; + if (odm_rec && !(success = early_mount_one(odm_rec))) goto done; + if (system_rec && !(success = early_mount_one(system_rec))) goto done; + if (vendor_rec && !(success = early_mount_one(vendor_rec))) goto done; +done: device_close(); - - return true; + return success; } int main(int argc, char** argv) { From 05ff38ba43eb7a882873312f12fc019b42f37b34 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Thu, 16 Feb 2017 17:04:11 -0800 Subject: [PATCH 6/8] init: early_mount: disallow partitions to be verified at boot While technically possible, the verification at boot basically will block init for as long as the entire partition is read while nothing else is running. Disallow that as this is not going to be used anywhere. Bug: 27805372 Test: boot angler with verifyatboot fs_mgr option for early mounted vendor partition. That resulted in a panic() as expected. Change-Id: I9da5caa163cae8bce6dbfb630f0ed5605ea044a0 Signed-off-by: Sandeep Patil --- fs_mgr/fs_mgr_fstab.cpp | 5 +++++ fs_mgr/include/fs_mgr.h | 1 + init/init.cpp | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 48ddf29e8..10e70d6e5 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -557,6 +557,11 @@ int fs_mgr_is_verified(const struct fstab_rec *fstab) return fstab->fs_mgr_flags & MF_VERIFY; } +int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_VERIFYATBOOT; +} + int fs_mgr_is_encryptable(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE); diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 7b389cd1c..0402b5593 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -117,6 +117,7 @@ struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const ch int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab); int fs_mgr_is_nonremovable(const struct fstab_rec *fstab); int fs_mgr_is_verified(const struct fstab_rec *fstab); +int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab); int fs_mgr_is_encryptable(const struct fstab_rec *fstab); int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab); const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab); diff --git a/init/init.cpp b/init/init.cpp index 702186cfa..2399f5c6f 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -799,6 +799,14 @@ static bool early_mount() { return true; } + // don't allow verifyatboot for early mounted partitions + if ((odm_rec && fs_mgr_is_verifyatboot(odm_rec)) || + (system_rec && fs_mgr_is_verifyatboot(system_rec)) || + (vendor_rec && fs_mgr_is_verifyatboot(vendor_rec))) { + LOG(ERROR) << "Early mount partitions can't be verified at boot"; + return false; + } + // assume A/B device if we find 'slotselect' in any fstab entry bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) || (system_rec && fs_mgr_is_slotselect(system_rec)) || From e9da79bd4466d5bf0d445b90915a9f18942fc7fe Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Thu, 16 Feb 2017 18:13:38 -0800 Subject: [PATCH 7/8] init: early_mount: create device node for verity metadata partition Most devices pass the veritymode through 'androidboot.veritymode' kernel cmdline partition. However, for those who don't, the verity state is read from a different block device whose path it passed to "verify=" fs_mgr option in fstab. This change add support for such a case if the partition that needs to be mounted early requires this additional block device to load the verity state from. Note that, there can only be 1 partition to get the verity state regardless of the number of partitions we enable verity for. Bug: 27805372 Test: Test angler by removing the metdata argument in fstab when it boots fine. Tested by adding the argument when it fails to boot as veritymode gets set to EIO during early mount due to lack of access to properties as expected. TODO: fs_mgr must pull the veritymode from kernel cmdline or device tree by itself Change-Id: I9e62b8c1bf2c0ae0365677df697a0cbe9e5810c1 Signed-off-by: Sandeep Patil --- init/init.cpp | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index 2399f5c6f..05f2cfd66 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -791,6 +791,8 @@ static bool early_mount() { } // find out fstab records for odm, system and vendor + // TODO: add std::map so all required information about + // them can be gathered at once in a single loop fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm"); fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system"); fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor"); @@ -811,9 +813,29 @@ static bool early_mount() { bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) || (system_rec && fs_mgr_is_slotselect(system_rec)) || (vendor_rec && fs_mgr_is_slotselect(vendor_rec))); + + // check for verified partitions + bool need_verity = ((odm_rec && fs_mgr_is_verified(odm_rec)) || + (system_rec && fs_mgr_is_verified(system_rec)) || + (vendor_rec && fs_mgr_is_verified(vendor_rec))); + + // check if verity metadata is on a separate partition and get partition + // name from the end of the ->verity_loc path. verity state is not partition + // specific, so there must be only 1 additional partition that carries + // verity state. + std::string meta_partition; + if (odm_rec && odm_rec->verity_loc) { + meta_partition = basename(odm_rec->verity_loc); + } else if (system_rec && system_rec->verity_loc) { + meta_partition = basename(system_rec->verity_loc); + } else if (vendor_rec && vendor_rec->verity_loc) { + meta_partition = basename(vendor_rec->verity_loc); + } + bool found_odm = !odm_rec; bool found_system = !system_rec; bool found_vendor = !vendor_rec; + bool found_meta = meta_partition.empty(); int count_odm = 0, count_vendor = 0, count_system = 0; // create the devices we need.. @@ -863,6 +885,10 @@ static bool early_mount() { found_vendor = true; } + create_this_node = true; + } else if (!found_meta && (meta_partition == uevent->partition_name)) { + LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition"; + found_meta = true; create_this_node = true; } } @@ -871,7 +897,7 @@ static bool early_mount() { // node and stop coldboot. If this is a prefix matched // partition, create device node and continue. For everything // else skip the device node - if (found_odm && found_system && found_vendor) { + if (found_meta && found_odm && found_system && found_vendor) { ret = COLDBOOT_STOP; } else if (create_this_node) { ret = COLDBOOT_CREATE; @@ -882,10 +908,6 @@ static bool early_mount() { return ret; }); - // check for verified partitions - bool need_verity = ((odm_rec && fs_mgr_is_verified(odm_rec)) || - (system_rec && fs_mgr_is_verified(system_rec)) || - (vendor_rec && fs_mgr_is_verified(vendor_rec))); if (need_verity) { // create /dev/device mapper device_init("/sys/devices/virtual/misc/device-mapper", From 9de748f74558abf047045302b6fc46af7629eedb Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Thu, 16 Feb 2017 19:15:29 -0800 Subject: [PATCH 8/8] 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 --- fs_mgr/Android.mk | 3 +- fs_mgr/fs_mgr_avb.cpp | 24 +++++---- fs_mgr/fs_mgr_boot_config.cpp | 71 ++++++++++++++++++++++++ fs_mgr/fs_mgr_priv.h | 1 + fs_mgr/fs_mgr_priv_boot_config.h | 25 +++++++++ fs_mgr/fs_mgr_slotselect.cpp | 93 ++------------------------------ fs_mgr/fs_mgr_verity.cpp | 8 ++- 7 files changed, 120 insertions(+), 105 deletions(-) create mode 100644 fs_mgr/fs_mgr_boot_config.cpp create mode 100644 fs_mgr/fs_mgr_priv_boot_config.h diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 693942883..f1a7ad6dd 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk @@ -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 \ diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp index 68efb00a0..2cb7e3438 100644 --- a/fs_mgr/fs_mgr_avb.cpp +++ b/fs_mgr/fs_mgr_avb.cpp @@ -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: diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp new file mode 100644 index 000000000..ae442cff8 --- /dev/null +++ b/fs_mgr/fs_mgr_boot_config.cpp @@ -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 +#include +#include +#include + +#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 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; +} diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 79c27c425..478c145d3 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -19,6 +19,7 @@ #include #include +#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 diff --git a/fs_mgr/fs_mgr_priv_boot_config.h b/fs_mgr/fs_mgr_priv_boot_config.h new file mode 100644 index 000000000..74bb5eb07 --- /dev/null +++ b/fs_mgr/fs_mgr_priv_boot_config.h @@ -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 +#include + +bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val); + +#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */ diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp index b30417fdc..f3bba7b93 100644 --- a/fs_mgr/fs_mgr_slotselect.cpp +++ b/fs_mgr/fs_mgr_slotselect.cpp @@ -14,118 +14,31 @@ * limitations under the License. */ -#include -#include -#include -#include - -#include -#include #include -#include -#include - -#include -#include -#include -#include #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 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 { diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp index d72ac73de..2c9b0a974 100644 --- a/fs_mgr/fs_mgr_verity.cpp +++ b/fs_mgr/fs_mgr_verity.cpp @@ -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;