fs_mgr_overlayfs: Cleanup -user build stubs

* Categorize functions in fs_mgr_overlayfs.h into three classes:
  - Type 1: common and non-critical utilities.
  - Type 2: internal routines for facilitating remount.
  - Type 3: external entry points for users of fs_mgr_overlayfs, like
            fs_mgr_overlayfs_mount_all().
* Move type 1 to common utils header fs_mgr_priv.h & fs_mgr.cpp.
* Move type 2 to new private header fs_mgr_priv_overlayfs.h.
* Keep type 3 in fs_mgr_overlayfs.h.
* Move set-verity-state.cpp under fs_mgr so it can include
  fs_mgr_priv_overlayfs.h. File is reformatted as a result. We should
  eventually merge and dedup set-verity-state and fs_mgr_remount.
* Add myself to OWNERS for remount-related maintenance work.

Bug: 241179247
Bug: 241688845
Test: Full build -user and -userdebug build.
Test: Presubmit
Test: Treehugger run v2/android-gki/adb_remount
Change-Id: Id5fd0e2b12c693939d712a586dd553cc4d8bfeb1
This commit is contained in:
Yi-Yo Chiang 2022-09-21 22:10:33 +08:00
parent 0cba7afd67
commit ad06b405ee
14 changed files with 483 additions and 463 deletions

View file

@ -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",
],
}

View file

@ -2,3 +2,4 @@
bowgotsai@google.com
dvander@google.com
elsk@google.com
yochiang@google.com

View file

@ -22,6 +22,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <libgen.h>
#include <selinux/selinux.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -30,6 +31,7 @@
#include <sys/stat.h>
#include <sys/swap.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
@ -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;
}

View file

@ -56,6 +56,7 @@
#include <storage_literals/storage_literals.h>
#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<bool(const std::set<std::string>&)>&) {
}
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<bool(const std::set<std::string>&)>& 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;
}

View file

@ -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);

View file

@ -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 <string>
#include <fstab/fstab.h>
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

View file

@ -42,6 +42,8 @@
#include <libavb_user/libavb_user.h>
#include <libgsi/libgsid.h>
#include "fs_mgr_priv_overlayfs.h"
using namespace std::literals;
using android::fs_mgr::Fstab;
using android::fs_mgr::FstabEntry;

View file

@ -25,7 +25,6 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <fs_mgr_overlayfs.h>
#include <fs_mgr_vendor_overlay.h>
#include <fstab/fstab.h>

View file

@ -17,51 +17,21 @@
#pragma once
#include <functional>
#include <set>
#include <string>
#include <fstab/fstab.h>
#include <set>
#include <string>
#include <vector>
// 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<bool(const std::set<std::string>&)>& init);
void CleanupOldScratchFiles();
// Teardown overlays of all sources (cache dir, scratch device, DSU) for |mount_point|.
// Teardown all overlays if |mount_point| is empty.

258
fs_mgr/set-verity-state.cpp Normal file
View file

@ -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 <getopt.h>
#include <stdio.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <binder/ProcessState.h>
#include <cutils/android_reboot.h>
#include <fs_mgr_overlayfs.h>
#include <libavb_user/libavb_user.h>
#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<AvbOps, decltype(&avb_ops_user_free)> 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;
}

View file

@ -1 +0,0 @@
../.clang-format-2

View file

@ -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",
],
}

View file

@ -1,3 +0,0 @@
dvander@google.com
yochiang@google.com
bowgotsai@google.com

View file

@ -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 <getopt.h>
#include <stdio.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <binder/ProcessState.h>
#include <cutils/android_reboot.h>
#include <fs_mgr_overlayfs.h>
#include <libavb_user/libavb_user.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<AvbOps, decltype(&avb_ops_user_free)> 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;
}