/* * Copyright (C) 2017 The Android Open Source Project * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <stdio.h> #include <string.h> #include <sysexits.h> #include <android-base/properties.h> #include <libavb_user/libavb_user.h> 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 [--force] COMMAND\n" "\n" "Commands:\n" " %s get-verity - Prints whether verity is enabled in " "current slot.\n" " %s disable-verity - Disable verity in current slot.\n" " %s enable-verity - Enable verity in current slot.\n" " %s get-verification - Prints whether verification is enabled " "in current slot.\n" " %s disable-verification - Disable verification in current slot.\n" " %s enable-verification - Enable verification in current slot.\n", argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], 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. */ int do_set_verification(AvbOps* ops, const std::string& ab_suffix, bool enable_verification) { bool verification_enabled; if (!avb_user_verification_get( ops, ab_suffix.c_str(), &verification_enabled)) { fprintf(stderr, "Error getting whether verification is enabled.\n"); return EX_SOFTWARE; } if ((verification_enabled && enable_verification) || (!verification_enabled && !enable_verification)) { fprintf(stdout, "verification is already %s", verification_enabled ? "enabled" : "disabled"); if (ab_suffix != "") { fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } fprintf(stdout, ".\n"); 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; } fprintf(stdout, "Successfully %s verification", enable_verification ? "enabled" : "disabled"); if (ab_suffix != "") { fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } fprintf(stdout, ". Reboot the device for changes to take effect.\n"); return EX_OK; } /* Function to query if verification. The |ops| parameter should be an * |AvbOps| from libavb_user. */ int do_get_verification(AvbOps* ops, const std::string& ab_suffix) { bool verification_enabled; if (!avb_user_verification_get( ops, ab_suffix.c_str(), &verification_enabled)) { fprintf(stderr, "Error getting whether verification is enabled.\n"); return EX_SOFTWARE; } fprintf(stdout, "verification is %s", verification_enabled ? "enabled" : "disabled"); if (ab_suffix != "") { fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } fprintf(stdout, ".\n"); return EX_OK; } /* Function to enable and disable dm-verity. The |ops| parameter * should be an |AvbOps| from libavb_user. */ int do_set_verity(AvbOps* ops, const std::string& ab_suffix, bool enable_verity) { bool verity_enabled; if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) { fprintf(stderr, "Error getting whether verity is enabled.\n"); return EX_SOFTWARE; } if ((verity_enabled && enable_verity) || (!verity_enabled && !enable_verity)) { fprintf(stdout, "verity is already %s", verity_enabled ? "enabled" : "disabled"); if (ab_suffix != "") { fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } fprintf(stdout, ".\n"); 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; } fprintf( stdout, "Successfully %s verity", enable_verity ? "enabled" : "disabled"); if (ab_suffix != "") { fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } fprintf(stdout, ". Reboot the device for changes to take effect.\n"); return EX_OK; } /* Function to query if dm-verity is enabled. The |ops| parameter * should be an |AvbOps| from libavb_user. */ int do_get_verity(AvbOps* ops, const std::string& ab_suffix) { bool verity_enabled; if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) { fprintf(stderr, "Error getting whether verity is enabled.\n"); return EX_SOFTWARE; } fprintf(stdout, "verity is %s", verity_enabled ? "enabled" : "disabled"); if (ab_suffix != "") { fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str()); } fprintf(stdout, ".\n"); return EX_OK; } /* 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", ""); } } // 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); ret = EX_USAGE; goto out; } ops = avb_ops_user_new(); if (ops == nullptr) { fprintf(stderr, "Error getting AVB ops.\n"); ret = EX_SOFTWARE; goto out; } 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; } } 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); } return ret; }