1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <sysexits.h>
28
29 #include <android-base/properties.h>
30
31 #include <libavb_user/libavb_user.h>
32
33 namespace {
34
35 static bool g_opt_force = false;
36
37 /* Prints program usage to |where|. */
usage(FILE * where,int,char * argv[])38 void usage(FILE* where, int /* argc */, char* argv[]) {
39 fprintf(where,
40 "%s - command-line tool for AVB.\n"
41 "\n"
42 "Usage:\n"
43 " %s [--force] COMMAND\n"
44 "\n"
45 "Commands:\n"
46 " %s get-verity - Prints whether verity is enabled in "
47 "current slot.\n"
48 " %s disable-verity - Disable verity in current slot.\n"
49 " %s enable-verity - Enable verity in current slot.\n"
50 " %s get-verification - Prints whether verification is enabled "
51 "in current slot.\n"
52 " %s disable-verification - Disable verification in current slot.\n"
53 " %s enable-verification - Enable verification in current slot.\n",
54 argv[0],
55 argv[0],
56 argv[0],
57 argv[0],
58 argv[0],
59 argv[0],
60 argv[0],
61 argv[0]);
62 }
63
64 /* Returns true if device is in LOCKED mode and --force wasn't
65 * passed. In this case also prints diagnostic message to stderr as a
66 * side-effect.
67 */
is_locked_and_not_forced()68 bool is_locked_and_not_forced() {
69 std::string device_state;
70
71 device_state = android::base::GetProperty("ro.boot.vbmeta.device_state", "");
72 if (device_state == "locked" && !g_opt_force) {
73 fprintf(stderr,
74 "Manipulating vbmeta on a LOCKED device will likely cause the\n"
75 "device to fail booting with little chance of recovery.\n"
76 "\n"
77 "If you really want to do this, use the --force option.\n"
78 "\n"
79 "ONLY DO THIS IF YOU KNOW WHAT YOU ARE DOING.\n"
80 "\n");
81 return false;
82 }
83
84 return true;
85 }
86
87 /* Function to enable and disable verification. The |ops| parameter
88 * should be an |AvbOps| from libavb_user.
89 */
do_set_verification(AvbOps * ops,const std::string & ab_suffix,bool enable_verification)90 int do_set_verification(AvbOps* ops,
91 const std::string& ab_suffix,
92 bool enable_verification) {
93 bool verification_enabled;
94
95 if (!avb_user_verification_get(
96 ops, ab_suffix.c_str(), &verification_enabled)) {
97 fprintf(stderr, "Error getting whether verification is enabled.\n");
98 return EX_SOFTWARE;
99 }
100
101 if ((verification_enabled && enable_verification) ||
102 (!verification_enabled && !enable_verification)) {
103 fprintf(stdout,
104 "verification is already %s",
105 verification_enabled ? "enabled" : "disabled");
106 if (ab_suffix != "") {
107 fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
108 }
109 fprintf(stdout, ".\n");
110 return EX_OK;
111 }
112
113 if (!is_locked_and_not_forced()) {
114 return EX_NOPERM;
115 }
116
117 if (!avb_user_verification_set(ops, ab_suffix.c_str(), enable_verification)) {
118 fprintf(stderr, "Error setting verification.\n");
119 return EX_SOFTWARE;
120 }
121
122 fprintf(stdout,
123 "Successfully %s verification",
124 enable_verification ? "enabled" : "disabled");
125 if (ab_suffix != "") {
126 fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
127 }
128 fprintf(stdout, ". Reboot the device for changes to take effect.\n");
129
130 return EX_OK;
131 }
132
133 /* Function to query if verification. The |ops| parameter should be an
134 * |AvbOps| from libavb_user.
135 */
do_get_verification(AvbOps * ops,const std::string & ab_suffix)136 int do_get_verification(AvbOps* ops, const std::string& ab_suffix) {
137 bool verification_enabled;
138
139 if (!avb_user_verification_get(
140 ops, ab_suffix.c_str(), &verification_enabled)) {
141 fprintf(stderr, "Error getting whether verification is enabled.\n");
142 return EX_SOFTWARE;
143 }
144
145 fprintf(stdout,
146 "verification is %s",
147 verification_enabled ? "enabled" : "disabled");
148 if (ab_suffix != "") {
149 fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
150 }
151 fprintf(stdout, ".\n");
152
153 return EX_OK;
154 }
155
156 /* Function to enable and disable dm-verity. The |ops| parameter
157 * should be an |AvbOps| from libavb_user.
158 */
do_set_verity(AvbOps * ops,const std::string & ab_suffix,bool enable_verity)159 int do_set_verity(AvbOps* ops,
160 const std::string& ab_suffix,
161 bool enable_verity) {
162 bool verity_enabled;
163
164 if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) {
165 fprintf(stderr, "Error getting whether verity is enabled.\n");
166 return EX_SOFTWARE;
167 }
168
169 if ((verity_enabled && enable_verity) ||
170 (!verity_enabled && !enable_verity)) {
171 fprintf(stdout,
172 "verity is already %s",
173 verity_enabled ? "enabled" : "disabled");
174 if (ab_suffix != "") {
175 fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
176 }
177 fprintf(stdout, ".\n");
178 return EX_OK;
179 }
180
181 if (!is_locked_and_not_forced()) {
182 return EX_NOPERM;
183 }
184
185 if (!avb_user_verity_set(ops, ab_suffix.c_str(), enable_verity)) {
186 fprintf(stderr, "Error setting verity.\n");
187 return EX_SOFTWARE;
188 }
189
190 fprintf(
191 stdout, "Successfully %s verity", enable_verity ? "enabled" : "disabled");
192 if (ab_suffix != "") {
193 fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
194 }
195 fprintf(stdout, ". Reboot the device for changes to take effect.\n");
196
197 return EX_OK;
198 }
199
200 /* Function to query if dm-verity is enabled. The |ops| parameter
201 * should be an |AvbOps| from libavb_user.
202 */
do_get_verity(AvbOps * ops,const std::string & ab_suffix)203 int do_get_verity(AvbOps* ops, const std::string& ab_suffix) {
204 bool verity_enabled;
205
206 if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) {
207 fprintf(stderr, "Error getting whether verity is enabled.\n");
208 return EX_SOFTWARE;
209 }
210
211 fprintf(stdout, "verity is %s", verity_enabled ? "enabled" : "disabled");
212 if (ab_suffix != "") {
213 fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
214 }
215 fprintf(stdout, ".\n");
216
217 return EX_OK;
218 }
219
220 /* Helper function to get A/B suffix, if any. If the device isn't
221 * using A/B the empty string is returned. Otherwise either "_a",
222 * "_b", ... is returned.
223 */
get_ab_suffix()224 std::string get_ab_suffix() {
225 return android::base::GetProperty("ro.boot.slot_suffix", "");
226 }
227
228 } // namespace
229
230 enum class Command {
231 kNone,
232 kDisableVerity,
233 kEnableVerity,
234 kGetVerity,
235 kDisableVerification,
236 kEnableVerification,
237 kGetVerification,
238 };
239
main(int argc,char * argv[])240 int main(int argc, char* argv[]) {
241 int ret;
242 AvbOps* ops = nullptr;
243 std::string ab_suffix = get_ab_suffix();
244 Command cmd = Command::kNone;
245
246 if (argc < 2) {
247 usage(stderr, argc, argv);
248 ret = EX_USAGE;
249 goto out;
250 }
251
252 ops = avb_ops_user_new();
253 if (ops == nullptr) {
254 fprintf(stderr, "Error getting AVB ops.\n");
255 ret = EX_SOFTWARE;
256 goto out;
257 }
258
259 for (int n = 1; n < argc; n++) {
260 if (strcmp(argv[n], "--force") == 0) {
261 g_opt_force = true;
262 } else if (strcmp(argv[n], "disable-verity") == 0) {
263 cmd = Command::kDisableVerity;
264 } else if (strcmp(argv[n], "enable-verity") == 0) {
265 cmd = Command::kEnableVerity;
266 } else if (strcmp(argv[n], "get-verity") == 0) {
267 cmd = Command::kGetVerity;
268 } else if (strcmp(argv[n], "disable-verification") == 0) {
269 cmd = Command::kDisableVerification;
270 } else if (strcmp(argv[n], "enable-verification") == 0) {
271 cmd = Command::kEnableVerification;
272 } else if (strcmp(argv[n], "get-verification") == 0) {
273 cmd = Command::kGetVerification;
274 }
275 }
276
277 switch (cmd) {
278 case Command::kNone:
279 usage(stderr, argc, argv);
280 ret = EX_USAGE;
281 break;
282 case Command::kDisableVerity:
283 ret = do_set_verity(ops, ab_suffix, false);
284 break;
285 case Command::kEnableVerity:
286 ret = do_set_verity(ops, ab_suffix, true);
287 break;
288 case Command::kGetVerity:
289 ret = do_get_verity(ops, ab_suffix);
290 break;
291 case Command::kDisableVerification:
292 ret = do_set_verification(ops, ab_suffix, false);
293 break;
294 case Command::kEnableVerification:
295 ret = do_set_verification(ops, ab_suffix, true);
296 break;
297 case Command::kGetVerification:
298 ret = do_get_verification(ops, ab_suffix);
299 break;
300 }
301
302 out:
303 if (ops != nullptr) {
304 avb_ops_user_free(ops);
305 }
306 return ret;
307 }
308