diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 49761ac30..45cd3c0a3 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -254,3 +254,39 @@ cc_binary { "clean_scratch_files", ], } + +cc_binary { + name: "set-verity-state", + srcs: ["set-verity-state.cpp"], + shared_libs: [ + "libbase", + "libbinder", + "libcrypto", + "libcrypto_utils", + "libfs_mgr_binder", + "libutils", + ], + static_libs: [ + "libavb_user", + ], + header_libs: [ + "libcutils_headers", + ], + + cflags: ["-Werror"], + cppflags: [ + "-DALLOW_DISABLE_VERITY=0", + ], + product_variables: { + debuggable: { + cppflags: [ + "-UALLOW_DISABLE_VERITY", + "-DALLOW_DISABLE_VERITY=1", + ], + }, + }, + symlinks: [ + "enable-verity", + "disable-verity", + ], +} diff --git a/fs_mgr/OWNERS b/fs_mgr/OWNERS index c6f9054fa..6f1059bfb 100644 --- a/fs_mgr/OWNERS +++ b/fs_mgr/OWNERS @@ -2,3 +2,4 @@ bowgotsai@google.com dvander@google.com elsk@google.com +yochiang@google.com diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 9fe8e188a..27137a298 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -2359,3 +2361,49 @@ bool fs_mgr_load_verity_state(int* mode) { return true; } + +bool fs_mgr_filesystem_available(const std::string& filesystem) { + std::string filesystems; + if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false; + return filesystems.find("\t" + filesystem + "\n") != std::string::npos; +} + +std::string fs_mgr_get_context(const std::string& mount_point) { + char* ctx = nullptr; + if (getfilecon(mount_point.c_str(), &ctx) == -1) { + PERROR << "getfilecon " << mount_point; + return ""; + } + + std::string context(ctx); + free(ctx); + return context; +} + +OverlayfsValidResult fs_mgr_overlayfs_valid() { + // Overlayfs available in the kernel, and patched for override_creds? + if (access("/sys/module/overlay/parameters/override_creds", F_OK) == 0) { + return OverlayfsValidResult::kOverrideCredsRequired; + } + if (!fs_mgr_filesystem_available("overlay")) { + return OverlayfsValidResult::kNotSupported; + } + struct utsname uts; + if (uname(&uts) == -1) { + return OverlayfsValidResult::kNotSupported; + } + int major, minor; + if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { + return OverlayfsValidResult::kNotSupported; + } + if (major < 4) { + return OverlayfsValidResult::kOk; + } + if (major > 4) { + return OverlayfsValidResult::kNotSupported; + } + if (minor > 3) { + return OverlayfsValidResult::kNotSupported; + } + return OverlayfsValidResult::kOk; +} diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 1d8a45225..df26d8544 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -56,6 +56,7 @@ #include #include "fs_mgr_priv.h" +#include "fs_mgr_priv_overlayfs.h" #include "libfiemap/utility.h" using namespace std::literals; @@ -71,62 +72,9 @@ bool fs_mgr_access(const std::string& path) { return access(path.c_str(), F_OK) == 0; } -// determine if a filesystem is available -bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) { - std::string filesystems; - if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false; - return filesystems.find("\t" + filesystem + "\n") != std::string::npos; -} - const auto kLowerdirOption = "lowerdir="s; const auto kUpperdirOption = "upperdir="s; -} // namespace - -#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs - -bool fs_mgr_wants_overlayfs(FstabEntry*) { - return false; -} - -Fstab fs_mgr_overlayfs_candidate_list(const Fstab&) { - return {}; -} - -bool fs_mgr_overlayfs_mount_all(Fstab*) { - return false; -} - -bool fs_mgr_overlayfs_setup(const char*, bool*, bool) { - LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds"; - return false; -} - -OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char*, bool*) { - return OverlayfsTeardownResult::Ok; -} - -bool fs_mgr_overlayfs_is_setup() { - return false; -} - -namespace android { -namespace fs_mgr { - -void MapScratchPartitionIfNeeded(Fstab*, const std::function&)>&) { -} - -void CleanupOldScratchFiles() {} - -void TeardownAllOverlayForMountPoint(const std::string&) {} - -} // namespace fs_mgr -} // namespace android - -#else // ALLOW_ADBD_DISABLE_VERITY == 0 - -namespace { - bool fs_mgr_in_recovery() { // Check the existence of recovery binary instead of using the compile time // __ANDROID_RECOVERY__ macro. @@ -234,6 +182,28 @@ bool fs_mgr_update_blk_device(FstabEntry* entry) { return true; } +bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) { + struct statfs fs; + if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) || + (fs.f_type != EXT4_SUPER_MAGIC)) { + return false; + } + + android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC)); + if (fd < 0) return false; + + struct ext4_super_block sb; + if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) || + (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) { + return false; + } + + struct fs_info info; + if (ext4_parse_sb(&sb, &info) < 0) return false; + + return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0; +} + bool fs_mgr_overlayfs_enabled(FstabEntry* entry) { // readonly filesystem, can not be mount -o remount,rw // for squashfs, erofs or if free space is (near) zero making such a remount @@ -886,10 +856,10 @@ const std::string kMkExt4("/system/bin/mke2fs"); // Only a suggestion for _first_ try during mounting std::string fs_mgr_overlayfs_scratch_mount_type() { - if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("f2fs")) { + if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_filesystem_available("f2fs")) { return "f2fs"; } - if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("ext4")) { + if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_filesystem_available("ext4")) { return "ext4"; } return "auto"; @@ -1233,11 +1203,41 @@ bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab) { return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type); } -bool fs_mgr_overlayfs_invalid() { - if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true; +#if ALLOW_ADBD_DISABLE_VERITY +constexpr bool kAllowOverlayfs = true; +#else +constexpr bool kAllowOverlayfs = false; +#endif +// NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed(). +// Setup is allowed only if teardown is also allowed. +bool OverlayfsSetupAllowed(bool verbose = false) { + if (!kAllowOverlayfs) { + if (verbose) { + LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds"; + } + return false; + } + // Check mandatory kernel patches. + if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { + if (verbose) { + LOG(ERROR) << "Kernel does not support overlayfs"; + } + return false; + } // in recovery or fastbootd, not allowed! - return fs_mgr_in_recovery(); + if (fs_mgr_in_recovery()) { + if (verbose) { + LOG(ERROR) << "Unsupported overlayfs setup from recovery"; + } + return false; + } + return true; +} + +constexpr bool OverlayfsTeardownAllowed() { + // Never allow on non-debuggable build. + return kAllowOverlayfs; } } // namespace @@ -1331,7 +1331,7 @@ static void TryMountScratch() { } bool fs_mgr_overlayfs_mount_all(Fstab* fstab) { - if (fs_mgr_overlayfs_invalid()) { + if (!OverlayfsSetupAllowed()) { return false; } auto ret = true; @@ -1352,8 +1352,7 @@ bool fs_mgr_overlayfs_mount_all(Fstab* fstab) { } bool fs_mgr_overlayfs_setup(const char* mount_point, bool* want_reboot, bool just_disabled_verity) { - if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { - LOG(ERROR) << "Overlayfs is not supported"; + if (!OverlayfsSetupAllowed(/*verbose=*/true)) { return false; } @@ -1523,7 +1522,8 @@ static bool MapDsuScratchDevice(std::string* device) { return true; } -OverlayfsTeardownResult TeardownMountsAndScratch(const char* mount_point, bool* want_reboot) { +static OverlayfsTeardownResult TeardownMountsAndScratch(const char* mount_point, + bool* want_reboot) { bool should_destroy_scratch = false; auto rv = OverlayfsTeardownResult::Ok; for (const auto& overlay_mount_point : OverlayMountPoints()) { @@ -1555,6 +1555,10 @@ OverlayfsTeardownResult TeardownMountsAndScratch(const char* mount_point, bool* // Returns false if teardown not permitted. If something is altered, set *want_reboot. OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point, bool* want_reboot) { + if (!OverlayfsTeardownAllowed()) { + // Nothing to teardown. + return OverlayfsTeardownResult::Ok; + } // If scratch exists, but is not mounted, lets gain access to clean // specific override entries. auto mount_scratch = false; @@ -1577,12 +1581,14 @@ OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point, bool* } bool fs_mgr_overlayfs_is_setup() { + if (!OverlayfsSetupAllowed()) { + return false; + } if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true; Fstab fstab; if (!ReadDefaultFstab(&fstab)) { return false; } - if (fs_mgr_overlayfs_invalid()) return false; for (const auto& entry : fs_mgr_overlayfs_candidate_list(fstab)) { if (fs_mgr_is_verity_enabled(entry)) continue; if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) return true; @@ -1595,7 +1601,7 @@ namespace fs_mgr { void MapScratchPartitionIfNeeded(Fstab* fstab, const std::function&)>& init) { - if (fs_mgr_overlayfs_invalid()) { + if (!OverlayfsSetupAllowed()) { return; } if (GetEntryForMountPoint(fstab, kScratchMountPoint) != nullptr) { @@ -1632,6 +1638,9 @@ void MapScratchPartitionIfNeeded(Fstab* fstab, } void CleanupOldScratchFiles() { + if (!OverlayfsTeardownAllowed()) { + return; + } if (!ScratchIsOnData()) { return; } @@ -1641,6 +1650,9 @@ void CleanupOldScratchFiles() { } void TeardownAllOverlayForMountPoint(const std::string& mount_point) { + if (!OverlayfsTeardownAllowed()) { + return; + } if (!fs_mgr_in_recovery()) { LERROR << __FUNCTION__ << "(): must be called within recovery."; return; @@ -1701,8 +1713,6 @@ void TeardownAllOverlayForMountPoint(const std::string& mount_point) { } // namespace fs_mgr } // namespace android -#endif // ALLOW_ADBD_DISABLE_VERITY != 0 - bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) { Fstab fstab; if (!ReadFstabFromFile("/proc/mounts", &fstab)) { @@ -1722,65 +1732,3 @@ bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overl } return false; } - -bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) { - struct statfs fs; - if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) || - (fs.f_type != EXT4_SUPER_MAGIC)) { - return false; - } - - android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC)); - if (fd < 0) return false; - - struct ext4_super_block sb; - if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) || - (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) { - return false; - } - - struct fs_info info; - if (ext4_parse_sb(&sb, &info) < 0) return false; - - return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0; -} - -std::string fs_mgr_get_context(const std::string& mount_point) { - char* ctx = nullptr; - if (getfilecon(mount_point.c_str(), &ctx) == -1) { - PLOG(ERROR) << "getfilecon " << mount_point; - return ""; - } - - std::string context(ctx); - free(ctx); - return context; -} - -OverlayfsValidResult fs_mgr_overlayfs_valid() { - // Overlayfs available in the kernel, and patched for override_creds? - if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) { - return OverlayfsValidResult::kOverrideCredsRequired; - } - if (!fs_mgr_overlayfs_filesystem_available("overlay")) { - return OverlayfsValidResult::kNotSupported; - } - struct utsname uts; - if (uname(&uts) == -1) { - return OverlayfsValidResult::kNotSupported; - } - int major, minor; - if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { - return OverlayfsValidResult::kNotSupported; - } - if (major < 4) { - return OverlayfsValidResult::kOk; - } - if (major > 4) { - return OverlayfsValidResult::kNotSupported; - } - if (minor > 3) { - return OverlayfsValidResult::kNotSupported; - } - return OverlayfsValidResult::kOk; -} diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index c5e477cff..46f54cc79 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -99,6 +99,16 @@ bool fs_mgr_is_f2fs(const std::string& blk_device); bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab); +bool fs_mgr_filesystem_available(const std::string& filesystem); +std::string fs_mgr_get_context(const std::string& mount_point); + +enum class OverlayfsValidResult { + kNotSupported = 0, + kOk, + kOverrideCredsRequired, +}; +OverlayfsValidResult fs_mgr_overlayfs_valid(); + namespace android { namespace fs_mgr { bool UnmapDevice(const std::string& name); diff --git a/fs_mgr/fs_mgr_priv_overlayfs.h b/fs_mgr/fs_mgr_priv_overlayfs.h new file mode 100644 index 000000000..45b954d18 --- /dev/null +++ b/fs_mgr/fs_mgr_priv_overlayfs.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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. + */ + +#pragma once + +#include + +#include + +bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true); +bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry); +android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab); + +// If "mount_point" is non-null, set up exactly one overlay. +// If "mount_point" is null, setup any overlays. +// +// If |want_reboot| is non-null, and a reboot is needed to apply overlays, then +// it will be true on return. The caller is responsible for initializing it. +bool fs_mgr_overlayfs_setup(const char* mount_point = nullptr, bool* want_reboot = nullptr, + bool just_disabled_verity = true); + +enum class OverlayfsTeardownResult { + Ok, + Busy, // Indicates that overlays are still in use. + Error +}; +OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, + bool* want_reboot = nullptr); + +namespace android { +namespace fs_mgr { + +void CleanupOldScratchFiles(); + +} // namespace fs_mgr +} // namespace android diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp index a78f9453b..54c1c2c1d 100644 --- a/fs_mgr/fs_mgr_remount.cpp +++ b/fs_mgr/fs_mgr_remount.cpp @@ -42,6 +42,8 @@ #include #include +#include "fs_mgr_priv_overlayfs.h" + using namespace std::literals; using android::fs_mgr::Fstab; using android::fs_mgr::FstabEntry; diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp index 1372511a7..6b32b4d6f 100644 --- a/fs_mgr/fs_mgr_vendor_overlay.cpp +++ b/fs_mgr/fs_mgr_vendor_overlay.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h index 4d9b13f2e..bdaabbf07 100644 --- a/fs_mgr/include/fs_mgr_overlayfs.h +++ b/fs_mgr/include/fs_mgr_overlayfs.h @@ -17,51 +17,21 @@ #pragma once #include +#include +#include #include -#include -#include -#include +// Keep the list short and only add interfaces that must be exported public. -android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab); - -bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry); bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab); bool fs_mgr_overlayfs_is_setup(); -bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev); -bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true); -std::string fs_mgr_get_context(const std::string& mount_point); - -// If "mount_point" is non-null, set up exactly one overlay. -// If "mount_point" is null, setup any overlays. -// -// If |want_reboot| is non-null, and a reboot is needed to apply overlays, then -// it will be true on return. The caller is responsible for initializing it. -bool fs_mgr_overlayfs_setup(const char* mount_point = nullptr, bool* want_reboot = nullptr, - bool just_disabled_verity = true); - -enum class OverlayfsTeardownResult { - Ok, - Busy, // Indicates that overlays are still in use. - Error -}; -OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, - bool* want_reboot = nullptr); - -enum class OverlayfsValidResult { - kNotSupported = 0, - kOk, - kOverrideCredsRequired, -}; -OverlayfsValidResult fs_mgr_overlayfs_valid(); namespace android { namespace fs_mgr { void MapScratchPartitionIfNeeded(Fstab* fstab, const std::function&)>& init); -void CleanupOldScratchFiles(); // Teardown overlays of all sources (cache dir, scratch device, DSU) for |mount_point|. // Teardown all overlays if |mount_point| is empty. diff --git a/fs_mgr/set-verity-state.cpp b/fs_mgr/set-verity-state.cpp new file mode 100644 index 000000000..84ee01f48 --- /dev/null +++ b/fs_mgr/set-verity-state.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2019 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 +#include + +#include "fs_mgr_priv_overlayfs.h" + +using namespace std::string_literals; + +namespace { + +void print_usage() { + printf("Usage:\n" + "\tdisable-verity\n" + "\tenable-verity\n" + "\tset-verity-state [0|1]\n" + "Options:\n" + "\t-h --help\tthis help\n" + "\t-R --reboot\tautomatic reboot if needed for new settings to take effect\n" + "\t-v --verbose\tbe noisy\n"); +} + +#ifdef ALLOW_DISABLE_VERITY +const bool kAllowDisableVerity = true; +#else +const bool kAllowDisableVerity = false; +#endif + +static bool SetupOrTeardownOverlayfs(bool enable) { + bool want_reboot = false; + if (enable) { + if (!fs_mgr_overlayfs_setup(nullptr, &want_reboot)) { + LOG(ERROR) << "Overlayfs setup failed."; + return want_reboot; + } + if (want_reboot) { + printf("enabling overlayfs\n"); + } + } else { + auto rv = fs_mgr_overlayfs_teardown(nullptr, &want_reboot); + if (rv == OverlayfsTeardownResult::Error) { + LOG(ERROR) << "Overlayfs teardown failed."; + return want_reboot; + } + if (rv == OverlayfsTeardownResult::Busy) { + LOG(ERROR) << "Overlayfs is still active until reboot."; + return true; + } + if (want_reboot) { + printf("disabling overlayfs\n"); + } + } + return want_reboot; +} + +/* Helper function to get A/B suffix, if any. If the device isn't + * using A/B the empty string is returned. Otherwise either "_a", + * "_b", ... is returned. + */ +std::string get_ab_suffix() { + return android::base::GetProperty("ro.boot.slot_suffix", ""); +} + +bool is_avb_device_locked() { + return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked"; +} + +bool is_debuggable() { + return android::base::GetBoolProperty("ro.debuggable", false); +} + +bool is_using_avb() { + // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by + // contract, androidboot.vbmeta.digest is set by the bootloader + // when using AVB). + return !android::base::GetProperty("ro.boot.vbmeta.digest", "").empty(); +} + +[[noreturn]] void reboot(const std::string& name) { + LOG(INFO) << "Rebooting device for new settings to take effect"; + ::sync(); + android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot," + name); + ::sleep(60); + LOG(ERROR) << "Failed to reboot"; + ::exit(1); +} + +struct SetVerityStateResult { + bool success = false; + bool want_reboot = false; +}; + +/* Use AVB to turn verity on/off */ +SetVerityStateResult SetVerityState(bool enable_verity) { + std::string ab_suffix = get_ab_suffix(); + bool verity_enabled = false; + + if (is_avb_device_locked()) { + LOG(ERROR) << "Device must be bootloader unlocked to change verity state"; + return {}; + } + + std::unique_ptr ops(avb_ops_user_new(), + &avb_ops_user_free); + if (!ops) { + LOG(ERROR) << "Error getting AVB ops"; + return {}; + } + + if (!avb_user_verity_get(ops.get(), ab_suffix.c_str(), &verity_enabled)) { + LOG(ERROR) << "Error getting verity state"; + return {}; + } + + if ((verity_enabled && enable_verity) || (!verity_enabled && !enable_verity)) { + LOG(INFO) << "Verity is already " << (verity_enabled ? "enabled" : "disabled"); + return {.success = true, .want_reboot = false}; + } + + if (!avb_user_verity_set(ops.get(), ab_suffix.c_str(), enable_verity)) { + LOG(ERROR) << "Error setting verity state"; + return {}; + } + + LOG(INFO) << "Successfully " << (enable_verity ? "enabled" : "disabled") << " verity"; + return {.success = true, .want_reboot = true}; +} + +class MyLogger { + public: + explicit MyLogger(bool verbose) : verbose_(verbose) {} + + void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag, + const char* file, unsigned int line, const char* message) { + // Hide log starting with '[fs_mgr]' unless it's an error. + if (verbose_ || severity >= android::base::ERROR || message[0] != '[') { + fprintf(stderr, "%s\n", message); + } + logd_(id, severity, tag, file, line, message); + } + + private: + android::base::LogdLogger logd_; + bool verbose_; +}; + +} // namespace + +int main(int argc, char* argv[]) { + bool auto_reboot = false; + bool verbose = false; + + struct option longopts[] = { + {"help", no_argument, nullptr, 'h'}, + {"reboot", no_argument, nullptr, 'R'}, + {"verbose", no_argument, nullptr, 'v'}, + {0, 0, nullptr, 0}, + }; + for (int opt; (opt = ::getopt_long(argc, argv, "hRv", longopts, nullptr)) != -1;) { + switch (opt) { + case 'h': + print_usage(); + return 0; + case 'R': + auto_reboot = true; + break; + case 'v': + verbose = true; + break; + default: + print_usage(); + return 1; + } + } + + android::base::InitLogging(argv, MyLogger(verbose)); + + bool enable_verity = false; + const std::string progname = getprogname(); + if (progname == "enable-verity") { + enable_verity = true; + } else if (progname == "disable-verity") { + enable_verity = false; + } else if (optind < argc && (argv[optind] == "1"s || argv[optind] == "0"s)) { + // progname "set-verity-state" + enable_verity = (argv[optind] == "1"s); + } else { + print_usage(); + return 1; + } + + if (!kAllowDisableVerity || !is_debuggable()) { + errno = EPERM; + PLOG(ERROR) << "Cannot disable/enable verity on user build"; + return 1; + } + + if (getuid() != 0) { + errno = EACCES; + PLOG(ERROR) << "Must be running as root (adb root)"; + return 1; + } + + if (!is_using_avb()) { + LOG(ERROR) << "Expected AVB device, VB1.0 is no longer supported"; + return 1; + } + + int exit_code = 0; + bool want_reboot = false; + + auto ret = SetVerityState(enable_verity); + if (ret.success) { + want_reboot |= ret.want_reboot; + } else { + exit_code = 1; + } + + // Disable any overlayfs unconditionally if we want verity enabled. + // Enable overlayfs only if verity is successfully disabled or is already disabled. + if (enable_verity || ret.success) { + // Start a threadpool to service waitForService() callbacks as + // fs_mgr_overlayfs_* might call waitForService() to get the image service. + android::ProcessState::self()->startThreadPool(); + want_reboot |= SetupOrTeardownOverlayfs(!enable_verity); + } + + if (want_reboot) { + if (auto_reboot) { + reboot(progname); + } + printf("Reboot the device for new settings to take effect\n"); + } + + return exit_code; +} diff --git a/set-verity-state/.clang-format b/set-verity-state/.clang-format deleted file mode 120000 index fd0645fdf..000000000 --- a/set-verity-state/.clang-format +++ /dev/null @@ -1 +0,0 @@ -../.clang-format-2 \ No newline at end of file diff --git a/set-verity-state/Android.bp b/set-verity-state/Android.bp deleted file mode 100644 index f40118b7a..000000000 --- a/set-verity-state/Android.bp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 The Android Open Source Project - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_binary { - name: "set-verity-state", - srcs: ["set-verity-state.cpp"], - shared_libs: [ - "libbase", - "libbinder", - "libcrypto", - "libcrypto_utils", - "libfs_mgr_binder", - "libutils", - ], - static_libs: [ - "libavb_user", - ], - header_libs: [ - "libcutils_headers", - ], - - cflags: ["-Werror"], - cppflags: [ - "-DALLOW_DISABLE_VERITY=0", - ], - product_variables: { - debuggable: { - cppflags: [ - "-UALLOW_DISABLE_VERITY", - "-DALLOW_DISABLE_VERITY=1", - ], - }, - }, - symlinks: [ - "enable-verity", - "disable-verity", - ], -} diff --git a/set-verity-state/OWNERS b/set-verity-state/OWNERS deleted file mode 100644 index e8494509e..000000000 --- a/set-verity-state/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -dvander@google.com -yochiang@google.com -bowgotsai@google.com diff --git a/set-verity-state/set-verity-state.cpp b/set-verity-state/set-verity-state.cpp deleted file mode 100644 index 2b9c0ca91..000000000 --- a/set-verity-state/set-verity-state.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2019 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 -#include - -using namespace std::string_literals; - -namespace { - -void print_usage() { - printf( - "Usage:\n" - "\tdisable-verity\n" - "\tenable-verity\n" - "\tset-verity-state [0|1]\n" - "Options:\n" - "\t-h --help\tthis help\n" - "\t-R --reboot\tautomatic reboot if needed for new settings to take effect\n" - "\t-v --verbose\tbe noisy\n"); -} - -#ifdef ALLOW_DISABLE_VERITY -const bool kAllowDisableVerity = true; -#else -const bool kAllowDisableVerity = false; -#endif - -static bool SetupOrTeardownOverlayfs(bool enable) { - bool want_reboot = false; - if (enable) { - if (!fs_mgr_overlayfs_setup(nullptr, &want_reboot)) { - LOG(ERROR) << "Overlayfs setup failed."; - return want_reboot; - } - if (want_reboot) { - printf("enabling overlayfs\n"); - } - } else { - auto rv = fs_mgr_overlayfs_teardown(nullptr, &want_reboot); - if (rv == OverlayfsTeardownResult::Error) { - LOG(ERROR) << "Overlayfs teardown failed."; - return want_reboot; - } - if (rv == OverlayfsTeardownResult::Busy) { - LOG(ERROR) << "Overlayfs is still active until reboot."; - return true; - } - if (want_reboot) { - printf("disabling overlayfs\n"); - } - } - return want_reboot; -} - -/* Helper function to get A/B suffix, if any. If the device isn't - * using A/B the empty string is returned. Otherwise either "_a", - * "_b", ... is returned. - */ -std::string get_ab_suffix() { - return android::base::GetProperty("ro.boot.slot_suffix", ""); -} - -bool is_avb_device_locked() { - return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked"; -} - -bool is_debuggable() { - return android::base::GetBoolProperty("ro.debuggable", false); -} - -bool is_using_avb() { - // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by - // contract, androidboot.vbmeta.digest is set by the bootloader - // when using AVB). - return !android::base::GetProperty("ro.boot.vbmeta.digest", "").empty(); -} - -[[noreturn]] void reboot(const std::string& name) { - LOG(INFO) << "Rebooting device for new settings to take effect"; - ::sync(); - android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot," + name); - ::sleep(60); - LOG(ERROR) << "Failed to reboot"; - ::exit(1); -} - -struct SetVerityStateResult { - bool success = false; - bool want_reboot = false; -}; - -/* Use AVB to turn verity on/off */ -SetVerityStateResult SetVerityState(bool enable_verity) { - std::string ab_suffix = get_ab_suffix(); - bool verity_enabled = false; - - if (is_avb_device_locked()) { - LOG(ERROR) << "Device must be bootloader unlocked to change verity state"; - return {}; - } - - std::unique_ptr ops(avb_ops_user_new(), &avb_ops_user_free); - if (!ops) { - LOG(ERROR) << "Error getting AVB ops"; - return {}; - } - - if (!avb_user_verity_get(ops.get(), ab_suffix.c_str(), &verity_enabled)) { - LOG(ERROR) << "Error getting verity state"; - return {}; - } - - if ((verity_enabled && enable_verity) || (!verity_enabled && !enable_verity)) { - LOG(INFO) << "Verity is already " << (verity_enabled ? "enabled" : "disabled"); - return {.success = true, .want_reboot = false}; - } - - if (!avb_user_verity_set(ops.get(), ab_suffix.c_str(), enable_verity)) { - LOG(ERROR) << "Error setting verity state"; - return {}; - } - - LOG(INFO) << "Successfully " << (enable_verity ? "enabled" : "disabled") << " verity"; - return {.success = true, .want_reboot = true}; -} - -class MyLogger { - public: - explicit MyLogger(bool verbose) : verbose_(verbose) {} - - void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag, - const char* file, unsigned int line, const char* message) { - // Hide log starting with '[fs_mgr]' unless it's an error. - if (verbose_ || severity >= android::base::ERROR || message[0] != '[') { - fprintf(stderr, "%s\n", message); - } - logd_(id, severity, tag, file, line, message); - } - - private: - android::base::LogdLogger logd_; - bool verbose_; -}; - -} // namespace - -int main(int argc, char* argv[]) { - bool auto_reboot = false; - bool verbose = false; - - struct option longopts[] = { - {"help", no_argument, nullptr, 'h'}, - {"reboot", no_argument, nullptr, 'R'}, - {"verbose", no_argument, nullptr, 'v'}, - {0, 0, nullptr, 0}, - }; - for (int opt; (opt = ::getopt_long(argc, argv, "hRv", longopts, nullptr)) != -1;) { - switch (opt) { - case 'h': - print_usage(); - return 0; - case 'R': - auto_reboot = true; - break; - case 'v': - verbose = true; - break; - default: - print_usage(); - return 1; - } - } - - android::base::InitLogging(argv, MyLogger(verbose)); - - bool enable_verity = false; - const std::string progname = getprogname(); - if (progname == "enable-verity") { - enable_verity = true; - } else if (progname == "disable-verity") { - enable_verity = false; - } else if (optind < argc && (argv[optind] == "1"s || argv[optind] == "0"s)) { - // progname "set-verity-state" - enable_verity = (argv[optind] == "1"s); - } else { - print_usage(); - return 1; - } - - if (!kAllowDisableVerity || !is_debuggable()) { - errno = EPERM; - PLOG(ERROR) << "Cannot disable/enable verity on user build"; - return 1; - } - - if (getuid() != 0) { - errno = EACCES; - PLOG(ERROR) << "Must be running as root (adb root)"; - return 1; - } - - if (!is_using_avb()) { - LOG(ERROR) << "Expected AVB device, VB1.0 is no longer supported"; - return 1; - } - - int exit_code = 0; - bool want_reboot = false; - - auto ret = SetVerityState(enable_verity); - if (ret.success) { - want_reboot |= ret.want_reboot; - } else { - exit_code = 1; - } - - // Disable any overlayfs unconditionally if we want verity enabled. - // Enable overlayfs only if verity is successfully disabled or is already disabled. - if (enable_verity || ret.success) { - // Start a threadpool to service waitForService() callbacks as - // fs_mgr_overlayfs_* might call waitForService() to get the image service. - android::ProcessState::self()->startThreadPool(); - want_reboot |= SetupOrTeardownOverlayfs(!enable_verity); - } - - if (want_reboot) { - if (auto_reboot) { - reboot(progname); - } - printf("Reboot the device for new settings to take effect\n"); - } - - return exit_code; -}