avbctl: Require --force option if in LOCKED mode.
Bail and print a nice little warning if the user tries to rewrite
vbmeta if the device is locked. This is to help protect the user from
potentially bricking his device.
device:/ # avbctl disable-verity
Manipulating vbmeta on a LOCKED device will likely cause the
device to fail booting with little chance of recovery.
If you really want to do this, use the --force option.
ONLY DO THIS IF YOU KNOW WHAT YOU ARE DOING.
77|device:/ # avbctl --force disable-verity
Successfully disabled verity on slot with suffix _a. Reboot the device for changes to take effect.
device:/ #
Bug: 64482211
Test: Manually tested in both LOCKED and UNLOCKED mode.
Change-Id: Ica7b7df947ccb5fe515a3dae8c81eedfd594ca38
diff --git a/tools/avbctl/avbctl.cc b/tools/avbctl/avbctl.cc
index d0922b3..480edc1 100644
--- a/tools/avbctl/avbctl.cc
+++ b/tools/avbctl/avbctl.cc
@@ -32,13 +32,15 @@
namespace {
+static bool g_opt_force = false;
+
/* Prints program usage to |where|. */
void usage(FILE* where, int /* argc */, char* argv[]) {
fprintf(where,
"%s - command-line tool for AVB.\n"
"\n"
"Usage:\n"
- " %s COMMAND\n"
+ " %s [--force] COMMAND\n"
"\n"
"Commands:\n"
" %s get-verity - Prints whether verity is enabled in "
@@ -59,6 +61,29 @@
argv[0]);
}
+/* Returns true if device is in LOCKED mode and --force wasn't
+ * passed. In this case also prints diagnostic message to stderr as a
+ * side-effect.
+ */
+bool is_locked_and_not_forced() {
+ std::string device_state;
+
+ device_state = android::base::GetProperty("ro.boot.vbmeta.device_state", "");
+ if (device_state == "locked" && !g_opt_force) {
+ fprintf(stderr,
+ "Manipulating vbmeta on a LOCKED device will likely cause the\n"
+ "device to fail booting with little chance of recovery.\n"
+ "\n"
+ "If you really want to do this, use the --force option.\n"
+ "\n"
+ "ONLY DO THIS IF YOU KNOW WHAT YOU ARE DOING.\n"
+ "\n");
+ return false;
+ }
+
+ return true;
+}
+
/* Function to enable and disable verification. The |ops| parameter
* should be an |AvbOps| from libavb_user.
*/
@@ -85,6 +110,10 @@
return EX_OK;
}
+ if (!is_locked_and_not_forced()) {
+ return EX_NOPERM;
+ }
+
if (!avb_user_verification_set(ops, ab_suffix.c_str(), enable_verification)) {
fprintf(stderr, "Error setting verification.\n");
return EX_SOFTWARE;
@@ -149,6 +178,10 @@
return EX_OK;
}
+ if (!is_locked_and_not_forced()) {
+ return EX_NOPERM;
+ }
+
if (!avb_user_verity_set(ops, ab_suffix.c_str(), enable_verity)) {
fprintf(stderr, "Error setting verity.\n");
return EX_SOFTWARE;
@@ -206,10 +239,21 @@
} // namespace
+enum class Command {
+ kNone,
+ kDisableVerity,
+ kEnableVerity,
+ kGetVerity,
+ kDisableVerification,
+ kEnableVerification,
+ kGetVerification,
+};
+
int main(int argc, char* argv[]) {
int ret;
AvbOps* ops = nullptr;
std::string ab_suffix = get_ab_suffix();
+ Command cmd = Command::kNone;
if (argc < 2) {
usage(stderr, argc, argv);
@@ -224,24 +268,49 @@
goto out;
}
- if (strcmp(argv[1], "disable-verity") == 0) {
- ret = do_set_verity(ops, ab_suffix, false);
- } else if (strcmp(argv[1], "enable-verity") == 0) {
- ret = do_set_verity(ops, ab_suffix, true);
- } else if (strcmp(argv[1], "get-verity") == 0) {
- ret = do_get_verity(ops, ab_suffix);
- } else if (strcmp(argv[1], "disable-verification") == 0) {
- ret = do_set_verification(ops, ab_suffix, false);
- } else if (strcmp(argv[1], "enable-verification") == 0) {
- ret = do_set_verification(ops, ab_suffix, true);
- } else if (strcmp(argv[1], "get-verification") == 0) {
- ret = do_get_verification(ops, ab_suffix);
- } else {
- usage(stderr, argc, argv);
- ret = EX_USAGE;
+ for (int n = 1; n < argc; n++) {
+ if (strcmp(argv[n], "--force") == 0) {
+ g_opt_force = true;
+ } else if (strcmp(argv[n], "disable-verity") == 0) {
+ cmd = Command::kDisableVerity;
+ } else if (strcmp(argv[n], "enable-verity") == 0) {
+ cmd = Command::kEnableVerity;
+ } else if (strcmp(argv[n], "get-verity") == 0) {
+ cmd = Command::kGetVerity;
+ } else if (strcmp(argv[n], "disable-verification") == 0) {
+ cmd = Command::kDisableVerification;
+ } else if (strcmp(argv[n], "enable-verification") == 0) {
+ cmd = Command::kEnableVerification;
+ } else if (strcmp(argv[n], "get-verification") == 0) {
+ cmd = Command::kGetVerification;
+ }
}
- ret = EX_OK;
+ switch (cmd) {
+ case Command::kNone:
+ usage(stderr, argc, argv);
+ ret = EX_USAGE;
+ break;
+ case Command::kDisableVerity:
+ ret = do_set_verity(ops, ab_suffix, false);
+ break;
+ case Command::kEnableVerity:
+ ret = do_set_verity(ops, ab_suffix, true);
+ break;
+ case Command::kGetVerity:
+ ret = do_get_verity(ops, ab_suffix);
+ break;
+ case Command::kDisableVerification:
+ ret = do_set_verification(ops, ab_suffix, false);
+ break;
+ case Command::kEnableVerification:
+ ret = do_set_verification(ops, ab_suffix, true);
+ break;
+ case Command::kGetVerification:
+ ret = do_get_verification(ops, ab_suffix);
+ break;
+ }
+
out:
if (ops != nullptr) {
avb_ops_user_free(ops);