xref: /aosp_15_r20/external/avb/tools/avbctl/avbctl.cc (revision d289c2ba6de359471b23d594623b906876bc48a0)
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