From 8bba52fc4bf1f2f84add7af5d9527ae923cf8ecc Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Thu, 6 Apr 2017 21:01:40 +0800 Subject: [PATCH 1/2] init: support early_mount with vboot 2.0 (external/avb/libavb) libavb requires verifying AVB metadata on all verified partitions at once. For example, /vbmeta, /boot, /system and /vendor. We need to invoke device_init() for those partitions even if we only want to early mount some of them, like /vendor and /system. This CL gets all AVB partitions and the early mount partitions from device tree through "firmware/android/vbmeta" and "firmware/fstab", respectively. The following is an example to early mount /vendor partition on bullhead: firmware { android { compatible = "android,firmware"; vbmeta { compatible = "android,vbmeta"; parts = "boot,system,vendor"; by_name_prefix="/dev/block/platform/soc.0/f9824900.sdhci/by-name" }; fstab { compatible = "android,fstab"; vendor { compatible = "android,vendor"; dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,inode_readahead_blks=8"; fsmgr_flags = "wait,avb"; }; }; }; }; Bug: 33254008 Test: early mount /vendor with vboot 2.0 (AVB) on bullhead Test: early mount /system without dm-verity on bullhead Test: early mount /vendor with vboot 1.0 on sailfish Change-Id: I89a1f77c97124f309346b33d9e700544b92ecf05 --- init/init.cpp | 237 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 182 insertions(+), 55 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index 543f38ee7..6c09c99ce 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -61,6 +61,7 @@ #include "bootchart.h" #include "devices.h" #include "fs_mgr.h" +#include "fs_mgr_avb.h" #include "import_parser.h" #include "init_parser.h" #include "keychords.h" @@ -482,42 +483,73 @@ static void export_kernel_boot_props() { } } -static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android"; - -static bool is_dt_compatible() { - std::string dt_value; - std::string file_name = StringPrintf("%s/compatible", android_dt_dir); - - if (android::base::ReadFileToString(file_name, &dt_value)) { - // trim the trailing '\0' out, otherwise the comparison - // will produce false-negatives. - dt_value.resize(dt_value.size() - 1); - if (dt_value == "android,firmware") { +/* Reads the content of device tree file into dt_value. + * Returns true if the read is success, false otherwise. + */ +static bool read_dt_file(const std::string& file_name, std::string* dt_value) { + if (android::base::ReadFileToString(file_name, dt_value)) { + if (!dt_value->empty()) { + dt_value->pop_back(); // Trim the trailing '\0' out. return true; } } - return false; } -static bool is_dt_fstab_compatible() { - std::string dt_value; - std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab"); +static const std::string kAndroidDtDir("/proc/device-tree/firmware/android/"); - if (android::base::ReadFileToString(file_name, &dt_value)) { - dt_value.resize(dt_value.size() - 1); - if (dt_value == "android,fstab") { +static bool is_dt_value_expected(const std::string& dt_file_suffix, + const std::string& expected_value) { + std::string dt_value; + std::string file_name = kAndroidDtDir + dt_file_suffix; + + if (read_dt_file(file_name, &dt_value)) { + if (dt_value == expected_value) { return true; } } - return false; } +static inline bool is_dt_compatible() { + return is_dt_value_expected("compatible", "android,firmware"); +} + +static inline bool is_dt_fstab_compatible() { + return is_dt_value_expected("fstab/compatible", "android,fstab"); +} + +static inline bool is_dt_vbmeta_compatible() { + return is_dt_value_expected("vbmeta/compatible", "android,vbmeta"); +} + +// Gets the vbmeta config from device tree. Specifically, the 'parts' and 'by_name_prefix'. +// /{ +// firmware { +// android { +// vbmeta { +// compatible = "android,vbmeta"; +// parts = "vbmeta,boot,system,vendor" +// by_name_prefix="/dev/block/platform/soc.0/f9824900.sdhci/by-name/" +// }; +// }; +// }; +// } +static bool get_vbmeta_config_from_dt(std::string* vbmeta_partitions, + std::string* device_file_by_name_prefix) { + std::string file_name = kAndroidDtDir + "vbmeta/parts"; + if (!read_dt_file(file_name, vbmeta_partitions)) return false; + + file_name = kAndroidDtDir + "vbmeta/by_name_prefix"; + if (!read_dt_file(file_name, device_file_by_name_prefix)) return false; + + return true; +} + static void process_kernel_dt() { if (!is_dt_compatible()) return; - std::unique_ptrdir(opendir(android_dt_dir), closedir); + std::unique_ptr dir(opendir(kAndroidDtDir.c_str()), closedir); if (!dir) return; std::string dt_file; @@ -527,7 +559,7 @@ static void process_kernel_dt() { continue; } - std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name); + std::string file_name = kAndroidDtDir + dp->d_name; android::base::ReadFileToString(file_name, &dt_file); std::replace(dt_file.begin(), dt_file.end(), ',', '.'); @@ -920,38 +952,100 @@ static void set_usb_controller() { } } -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 << "'"; +// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX. +static void device_init_dm_device(const std::string& dm_device) { + const std::string device_name(basename(dm_device.c_str())); + const std::string syspath = "/sys/block/" + device_name; + + device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t { + if (uevent->device_name && device_name == uevent->device_name) { + LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device; + return COLDBOOT_STOP; + } + return COLDBOOT_CONTINUE; + }); + device_close(); +} + +static bool vboot_1_0_mount_partitions(const std::vector& fstab_recs) { + if (fstab_recs.empty()) return false; + + for (auto rec : fstab_recs) { + bool need_create_dm_device = false; + if (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 /* wait_for_verity_dev */); + if (ret == FS_MGR_SETUP_VERITY_DISABLED) { + LOG(INFO) << "verity disabled for '" << rec->mount_point << "'"; + } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) { + need_create_dm_device = true; + } else { + PLOG(ERROR) << "early_mount: failed to setup verity for '" << rec->mount_point + << "'"; + return false; + } + } + if (need_create_dm_device) { + // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX". + // Need to create it because ueventd isn't started during early mount. + device_init_dm_device(rec->blk_device); + } + if (fs_mgr_do_mount_one(rec)) { + PLOG(ERROR) << "early_mount: failed to mount '" << 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; } +static bool vboot_2_0_mount_partitions(const std::vector& fstab_recs, + const std::string& device_file_by_name_prefix) { + if (fstab_recs.empty()) return false; + + FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open(device_file_by_name_prefix); + if (!avb_handle) { + LOG(INFO) << "Failed to Open FsManagerAvbHandle"; + return false; + } + + for (auto rec : fstab_recs) { + bool need_create_dm_device = false; + if (fs_mgr_is_avb(rec)) { + if (avb_handle->AvbHashtreeDisabled()) { + LOG(INFO) << "avb hashtree disabled for '" << rec->mount_point << "'"; + } else if (avb_handle->SetUpAvb(rec, false /* wait_for_verity_dev */)) { + need_create_dm_device = true; + } else { + PLOG(ERROR) << "early_mount: failed to set up AVB on partition: '" + << rec->mount_point << "'"; + return false; + } + } + if (need_create_dm_device) { + // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX". + // Need to create it because ueventd isn't started during early mount. + device_init_dm_device(rec->blk_device); + } + if (fs_mgr_do_mount_one(rec)) { + PLOG(ERROR) << "early_mount: failed to mount '" << rec->mount_point << "'"; + return false; + } + } + + return true; +} + +static bool mount_early_partitions(const std::vector& fstab_recs, + const std::string& device_file_by_name_prefix) { + if (is_dt_vbmeta_compatible()) { // AVB (external/avb) is used to setup dm-verity. + return vboot_2_0_mount_partitions(fstab_recs, device_file_by_name_prefix); + } else { + return vboot_1_0_mount_partitions(fstab_recs); + } +} + // Creates devices with uevent->partition_name matching one in the in/out // partition_names. Note that the partition_names MUST have A/B suffix // when A/B is used. Found partitions will then be removed from the @@ -994,12 +1088,10 @@ static void early_device_init(std::set* partition_names) { }); } -static bool get_early_partitions(const std::vector& early_fstab_recs, - std::set* out_partitions, bool* out_need_verity) { +static bool vboot_1_0_early_partitions(const std::vector& early_fstab_recs, + std::set* out_partitions, + bool* out_need_verity) { std::string meta_partition; - out_partitions->clear(); - *out_need_verity = false; - for (auto fstab_rec : early_fstab_recs) { // don't allow verifyatboot for early mounted partitions if (fs_mgr_is_verifyatboot(fstab_rec)) { @@ -1038,6 +1130,40 @@ static bool get_early_partitions(const std::vector& early_fstab_recs return true; } +// a.k.a. AVB (external/avb) +static bool vboot_2_0_early_partitions(std::set* out_partitions, bool* out_need_verity, + std::string* out_device_file_by_name_prefix) { + std::string vbmeta_partitions; + if (!get_vbmeta_config_from_dt(&vbmeta_partitions, out_device_file_by_name_prefix)) { + return false; + } + // libavb verifies AVB metadata on all verified partitions at once. + // e.g., The vbmeta_partitions will be "vbmeta,boot,system,vendor" + // for libavb to verify metadata, even if we only need to early mount /vendor. + std::vector partitions = android::base::Split(vbmeta_partitions, ","); + std::string ab_suffix = fs_mgr_get_slot_suffix(); + for (const auto& partition : partitions) { + out_partitions->emplace(partition + ab_suffix); + } + *out_need_verity = true; + return true; +} + +static bool get_early_partitions(const std::vector& early_fstab_recs, + std::set* out_partitions, bool* out_need_verity, + std::string* out_device_file_by_name_prefix) { + *out_need_verity = false; + out_partitions->clear(); + out_device_file_by_name_prefix->clear(); + + if (is_dt_vbmeta_compatible()) { // AVB (external/avb) is used to setup dm-verity. + return vboot_2_0_early_partitions(out_partitions, out_need_verity, + out_device_file_by_name_prefix); + } else { + return vboot_1_0_early_partitions(early_fstab_recs, out_partitions, out_need_verity); + } +} + /* Early mount vendor and ODM partitions. The fstab is read from device-tree. */ static bool early_mount() { // skip early mount if we're in recovery mode @@ -1072,9 +1198,11 @@ static bool early_mount() { if (early_fstab_recs.empty()) return true; bool need_verity; + std::string device_file_by_name_prefix; std::set partition_names; // partition_names MUST have A/B suffix when A/B is used - if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) { + if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity, + &device_file_by_name_prefix)) { return false; } @@ -1097,10 +1225,9 @@ static bool early_mount() { [&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; }); } - for (auto fstab_rec : early_fstab_recs) { - if (!early_mount_one(fstab_rec)) goto done; + if (mount_early_partitions(early_fstab_recs, device_file_by_name_prefix)) { + success = true; } - success = true; done: device_close(); From aaf70e77dc232fde152249bb6f66a227eab35a10 Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Thu, 2 Mar 2017 00:03:56 +0800 Subject: [PATCH 2/2] fs_mgr: support AVB in fs_mgr_update_verity_state() fs_mgr_update_verity_state() is invoked by 'verity_update_state' in init.rc. It will then set property "partition.system.verified" and "partition.vendor.verified" to verify_mode. We should support this for AVB as well. Also change the order of static libs in init to fix the build error after this change: system/extras/ext4_utils/ext4_crypt.cpp:69: error: undefined reference to 'property_get' Bug: 35416769 Test: Mount /system and /vendor with vboot 2.0 (AVB), check the following properties exist. - [partition.system.verified]: [2] - [partition.vendor.verified]: [2] Test: Mount /system and /vendor with vboot 1.0, check the following properties exist. - [partition.system.verified]: [0] - [partition.vendor.verified]: [0] Change-Id: I4328d66a8cb93f26e7960e620a0b2292d5f15900 --- fs_mgr/fs_mgr.cpp | 98 ++++++++++++++++++++++++++++++ fs_mgr/fs_mgr_priv.h | 1 + fs_mgr/fs_mgr_verity.cpp | 126 +-------------------------------------- fs_mgr/include/fs_mgr.h | 4 +- init/Android.mk | 2 +- init/builtins.cpp | 8 +-- 6 files changed, 107 insertions(+), 132 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 28da9dbd5..ea9cb375c 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -31,7 +31,10 @@ #include #include +#include + #include +#include #include #include #include @@ -50,6 +53,7 @@ #include "fs_mgr.h" #include "fs_mgr_avb.h" #include "fs_mgr_priv.h" +#include "fs_mgr_priv_dm_ioctl.h" #define KEY_LOC_PROP "ro.crypto.keyfile.userdata" #define KEY_IN_FOOTER "footer" @@ -1258,3 +1262,97 @@ int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_dev return 0; } + +bool fs_mgr_load_verity_state(int* mode) { + /* return the default mode, unless any of the verified partitions are in + * logging mode, in which case return that */ + *mode = VERITY_MODE_DEFAULT; + + std::unique_ptr fstab(fs_mgr_read_fstab_default(), + fs_mgr_free_fstab); + if (!fstab) { + LERROR << "Failed to read default fstab"; + return false; + } + + for (int i = 0; i < fstab->num_entries; i++) { + if (fs_mgr_is_avb(&fstab->recs[i])) { + *mode = VERITY_MODE_RESTART; // avb only supports restart mode. + break; + } else if (!fs_mgr_is_verified(&fstab->recs[i])) { + continue; + } + + int current; + if (load_verity_state(&fstab->recs[i], ¤t) < 0) { + continue; + } + if (current != VERITY_MODE_DEFAULT) { + *mode = current; + break; + } + } + + return true; +} + +bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) { + if (!callback) { + return false; + } + + int mode; + if (!fs_mgr_load_verity_state(&mode)) { + return false; + } + + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC))); + if (fd == -1) { + PERROR << "Error opening device mapper"; + return false; + } + + std::unique_ptr fstab(fs_mgr_read_fstab_default(), + fs_mgr_free_fstab); + if (!fstab) { + LERROR << "Failed to read default fstab"; + return false; + } + + alignas(dm_ioctl) char buffer[DM_BUF_SIZE]; + struct dm_ioctl* io = (struct dm_ioctl*)buffer; + bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true"; + + for (int i = 0; i < fstab->num_entries; i++) { + if (!fs_mgr_is_verified(&fstab->recs[i]) && !fs_mgr_is_avb(&fstab->recs[i])) { + continue; + } + + std::string mount_point; + if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) { + mount_point = "system"; + } else { + mount_point = basename(fstab->recs[i].mount_point); + } + + fs_mgr_verity_ioctl_init(io, mount_point, 0); + + const char* status; + if (ioctl(fd, DM_TABLE_STATUS, io)) { + if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) { + status = "V"; + } else { + PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point.c_str(); + continue; + } + } + + status = &buffer[io->data_start + sizeof(struct dm_target_spec)]; + + if (*status == 'C' || *status == 'V') { + callback(&fstab->recs[i], mount_point.c_str(), mode, *status); + } + } + + return true; +} diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index dedffd8d1..c985462af 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -115,5 +115,6 @@ int fs_mgr_test_access(const char *device); bool fs_mgr_update_for_slotselect(struct fstab *fstab); bool is_dt_compatible(); bool is_device_secure(); +int load_verity_state(struct fstab_rec* fstab, int* mode); #endif /* __CORE_FS_MGR_PRIV_H */ diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp index 8c7a8ca6d..0bf173bd8 100644 --- a/fs_mgr/fs_mgr_verity.cpp +++ b/fs_mgr/fs_mgr_verity.cpp @@ -653,8 +653,7 @@ static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset) offset); } -static int load_verity_state(struct fstab_rec *fstab, int *mode) -{ +int load_verity_state(struct fstab_rec* fstab, int* mode) { int match = 0; off64_t offset = 0; @@ -690,129 +689,6 @@ static int load_verity_state(struct fstab_rec *fstab, int *mode) return read_verity_state(fstab->verity_loc, offset, mode); } -int fs_mgr_load_verity_state(int *mode) -{ - int rc = -1; - int i; - int current; - struct fstab *fstab = NULL; - - /* return the default mode, unless any of the verified partitions are in - * logging mode, in which case return that */ - *mode = VERITY_MODE_DEFAULT; - - fstab = fs_mgr_read_fstab_default(); - if (!fstab) { - LERROR << "Failed to read default fstab"; - goto out; - } - - for (i = 0; i < fstab->num_entries; i++) { - if (!fs_mgr_is_verified(&fstab->recs[i])) { - continue; - } - - rc = load_verity_state(&fstab->recs[i], ¤t); - if (rc < 0) { - continue; - } - - if (current != VERITY_MODE_DEFAULT) { - *mode = current; - break; - } - } - - rc = 0; - -out: - if (fstab) { - fs_mgr_free_fstab(fstab); - } - - return rc; -} - -int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) -{ - alignas(dm_ioctl) char buffer[DM_BUF_SIZE]; - bool system_root = false; - std::string mount_point; - char propbuf[PROPERTY_VALUE_MAX]; - const char *status; - int fd = -1; - int i; - int mode; - int rc = -1; - struct dm_ioctl *io = (struct dm_ioctl *) buffer; - struct fstab *fstab = NULL; - - if (!callback) { - return -1; - } - - if (fs_mgr_load_verity_state(&mode) == -1) { - return -1; - } - - fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC)); - if (fd == -1) { - PERROR << "Error opening device mapper"; - goto out; - } - - property_get("ro.build.system_root_image", propbuf, ""); - system_root = !strcmp(propbuf, "true"); - fstab = fs_mgr_read_fstab_default(); - if (!fstab) { - LERROR << "Failed to read default fstab"; - goto out; - } - - for (i = 0; i < fstab->num_entries; i++) { - if (!fs_mgr_is_verified(&fstab->recs[i])) { - continue; - } - - if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) { - mount_point = "system"; - } else { - mount_point = basename(fstab->recs[i].mount_point); - } - - fs_mgr_verity_ioctl_init(io, mount_point, 0); - - if (ioctl(fd, DM_TABLE_STATUS, io)) { - if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) { - status = "V"; - } else { - PERROR << "Failed to query DM_TABLE_STATUS for " - << mount_point.c_str(); - continue; - } - } - - status = &buffer[io->data_start + sizeof(struct dm_target_spec)]; - - if (*status == 'C' || *status == 'V') { - callback(&fstab->recs[i], mount_point.c_str(), mode, *status); - } - } - - rc = 0; - -out: - if (fstab) { - fs_mgr_free_fstab(fstab); - } - - if (fd) { - close(fd); - } - - return rc; -} - static void update_verity_table_blk_device(char *blk_device, char **table) { std::string result, word; diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index cea70b449..12db6727f 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -113,8 +113,8 @@ int fs_mgr_do_tmpfs_mount(const char *n_name); int fs_mgr_unmount_all(struct fstab *fstab); int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size); -int fs_mgr_load_verity_state(int *mode); -int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback); +bool fs_mgr_load_verity_state(int* mode); +bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback); int fs_mgr_add_entry(struct fstab *fstab, const char *mount_point, const char *fs_type, const char *blk_device); diff --git a/init/Android.mk b/init/Android.mk index dbbf40a62..604529095 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -111,8 +111,8 @@ LOCAL_STATIC_LIBRARIES := \ libfec_rs \ libsquashfs_utils \ liblogwrap \ - libcutils \ libext4_utils \ + libcutils \ libbase \ libc \ libselinux \ diff --git a/init/builtins.cpp b/init/builtins.cpp index e1d9b94ee..2327cdfb4 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -677,11 +677,11 @@ static int do_sysclktz(const std::vector& args) { static int do_verity_load_state(const std::vector& args) { int mode = -1; - int rc = fs_mgr_load_verity_state(&mode); - if (rc == 0 && mode != VERITY_MODE_DEFAULT) { + bool loaded = fs_mgr_load_verity_state(&mode); + if (loaded && mode != VERITY_MODE_DEFAULT) { ActionManager::GetInstance().QueueEventTrigger("verity-logging"); } - return rc; + return loaded ? 0 : 1; } static void verity_update_property(fstab_rec *fstab, const char *mount_point, @@ -691,7 +691,7 @@ static void verity_update_property(fstab_rec *fstab, const char *mount_point, } static int do_verity_update_state(const std::vector& args) { - return fs_mgr_update_verity_state(verity_update_property); + return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1; } static int do_write(const std::vector& args) {