1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <inttypes.h>
20 #include <libavb_user/libavb_user.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <sys/mount.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26
27 #include <android-base/file.h>
28 #include <android-base/logging.h>
29 #include <android-base/properties.h>
30 #include <android-base/stringprintf.h>
31 #include <android-base/unique_fd.h>
32 #include <fs_mgr.h>
33 #include <fs_mgr_overlayfs.h>
34 #include <fstab/fstab.h>
35 #include <log/log_properties.h>
36
37 #include "fec/io.h"
38
39 #ifdef ALLOW_DISABLE_VERITY
40 static const bool kAllowDisableVerity = true;
41 #else
42 static const bool kAllowDisableVerity = false;
43 #endif
44
45 using android::base::unique_fd;
46
suggest_run_adb_root()47 static void suggest_run_adb_root() {
48 if (getuid() != 0) printf("Maybe run adb root?\n");
49 }
50
make_block_device_writable(const std::string & dev)51 static bool make_block_device_writable(const std::string& dev) {
52 unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
53 if (fd == -1) {
54 return false;
55 }
56
57 int OFF = 0;
58 bool result = (ioctl(fd.get(), BLKROSET, &OFF) != -1);
59 return result;
60 }
61
62 /* Turn verity on/off */
set_verity_enabled_state(const char * block_device,const char * mount_point,bool enable)63 static bool set_verity_enabled_state(const char* block_device, const char* mount_point,
64 bool enable) {
65 if (!make_block_device_writable(block_device)) {
66 printf("Could not make block device %s writable (%s).\n", block_device, strerror(errno));
67 return false;
68 }
69
70 fec::io fh(block_device, O_RDWR);
71
72 if (!fh) {
73 printf("Could not open block device %s (%s).\n", block_device, strerror(errno));
74 suggest_run_adb_root();
75 return false;
76 }
77
78 fec_verity_metadata metadata;
79
80 if (!fh.get_verity_metadata(metadata)) {
81 printf("Couldn't find verity metadata!\n");
82 return false;
83 }
84
85 if (!enable && metadata.disabled) {
86 printf("Verity already disabled on %s\n", mount_point);
87 return false;
88 }
89
90 if (enable && !metadata.disabled) {
91 printf("Verity already enabled on %s\n", mount_point);
92 return false;
93 }
94
95 if (!fh.set_verity_status(enable)) {
96 printf("Could not set verity %s flag on device %s with error %s\n",
97 enable ? "enabled" : "disabled", block_device, strerror(errno));
98 return false;
99 }
100
101 auto change = false;
102 errno = 0;
103 if (enable ? fs_mgr_overlayfs_teardown(mount_point, &change)
104 : fs_mgr_overlayfs_setup(nullptr, mount_point, &change)) {
105 if (change) {
106 printf("%s overlayfs for %s\n", enable ? "disabling" : "using", mount_point);
107 }
108 } else if (errno) {
109 int expected_errno = enable ? EBUSY : ENOENT;
110 if (errno != expected_errno) {
111 printf("Overlayfs %s for %s failed with error %s\n", enable ? "teardown" : "setup",
112 mount_point, strerror(errno));
113 }
114 }
115 printf("Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
116 return true;
117 }
118
119 /* Helper function to get A/B suffix, if any. If the device isn't
120 * using A/B the empty string is returned. Otherwise either "_a",
121 * "_b", ... is returned.
122 */
get_ab_suffix()123 static std::string get_ab_suffix() {
124 return android::base::GetProperty("ro.boot.slot_suffix", "");
125 }
126
is_avb_device_locked()127 static bool is_avb_device_locked() {
128 return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked";
129 }
130
overlayfs_setup(bool enable)131 static bool overlayfs_setup(bool enable) {
132 auto change = false;
133 errno = 0;
134 if (enable ? fs_mgr_overlayfs_teardown(nullptr, &change)
135 : fs_mgr_overlayfs_setup(nullptr, nullptr, &change)) {
136 if (change) {
137 printf("%s overlayfs\n", enable ? "disabling" : "using");
138 }
139 } else if (errno) {
140 printf("Overlayfs %s failed with error %s\n", enable ? "teardown" : "setup", strerror(errno));
141 suggest_run_adb_root();
142 }
143 return change;
144 }
145
146 /* Use AVB to turn verity on/off */
set_avb_verity_enabled_state(AvbOps * ops,bool enable_verity)147 static bool set_avb_verity_enabled_state(AvbOps* ops, bool enable_verity) {
148 std::string ab_suffix = get_ab_suffix();
149 bool verity_enabled;
150
151 if (is_avb_device_locked()) {
152 printf("Device is locked. Please unlock the device first\n");
153 return false;
154 }
155
156 if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) {
157 printf("Error getting verity state. Try adb root first?\n");
158 return false;
159 }
160
161 if ((verity_enabled && enable_verity) || (!verity_enabled && !enable_verity)) {
162 printf("verity is already %s\n", verity_enabled ? "enabled" : "disabled");
163 return false;
164 }
165
166 if (!avb_user_verity_set(ops, ab_suffix.c_str(), enable_verity)) {
167 printf("Error setting verity\n");
168 return false;
169 }
170
171 overlayfs_setup(enable_verity);
172 printf("Successfully %s verity\n", enable_verity ? "enabled" : "disabled");
173 return true;
174 }
175
main(int argc,char * argv[])176 int main(int argc, char* argv[]) {
177 if (argc == 0) {
178 LOG(FATAL) << "set-verity-state called with empty argv";
179 }
180
181 std::optional<bool> enable_opt;
182 std::string procname = android::base::Basename(argv[0]);
183 if (procname == "enable-verity") {
184 enable_opt = true;
185 } else if (procname == "disable-verity") {
186 enable_opt = false;
187 }
188
189 if (!enable_opt.has_value()) {
190 if (argc != 2) {
191 printf("usage: %s [1|0]\n", argv[0]);
192 return 1;
193 }
194
195 if (strcmp(argv[1], "1") == 0) {
196 enable_opt = true;
197 } else if (strcmp(argv[1], "0") == 0) {
198 enable_opt = false;
199 } else {
200 printf("usage: %s [1|0]\n", argv[0]);
201 return 1;
202 }
203 }
204
205 bool enable = enable_opt.value();
206
207 bool any_changed = false;
208
209 // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by
210 // contract, androidboot.vbmeta.digest is set by the bootloader
211 // when using AVB).
212 bool using_avb = !android::base::GetProperty("ro.boot.vbmeta.digest", "").empty();
213
214 // If using AVB, dm-verity is used on any build so we want it to
215 // be possible to disable/enable on any build (except USER). For
216 // VB1.0 dm-verity is only enabled on certain builds.
217 if (!using_avb) {
218 if (!kAllowDisableVerity) {
219 printf("%s only works for userdebug builds\n", argv[0]);
220 }
221
222 if (!android::base::GetBoolProperty("ro.secure", false)) {
223 overlayfs_setup(enable);
224 printf("verity not enabled - ENG build\n");
225 return 0;
226 }
227 }
228
229 // Should never be possible to disable dm-verity on a USER build
230 // regardless of using AVB or VB1.0.
231 if (!__android_log_is_debuggable()) {
232 printf("verity cannot be disabled/enabled - USER build\n");
233 return 0;
234 }
235
236 if (using_avb) {
237 // Yep, the system is using AVB.
238 AvbOps* ops = avb_ops_user_new();
239 if (ops == nullptr) {
240 printf("Error getting AVB ops\n");
241 return 1;
242 }
243 if (set_avb_verity_enabled_state(ops, enable)) {
244 any_changed = true;
245 }
246 avb_ops_user_free(ops);
247 } else {
248 // Not using AVB - assume VB1.0.
249
250 // read all fstab entries at once from all sources
251 android::fs_mgr::Fstab fstab;
252 if (!android::fs_mgr::ReadDefaultFstab(&fstab)) {
253 printf("Failed to read fstab\n");
254 suggest_run_adb_root();
255 return 0;
256 }
257
258 // Loop through entries looking for ones that verity manages.
259 for (const auto& entry : fstab) {
260 if (entry.fs_mgr_flags.verify) {
261 if (set_verity_enabled_state(entry.blk_device.c_str(), entry.mount_point.c_str(), enable)) {
262 any_changed = true;
263 }
264 }
265 }
266 }
267 if (!any_changed) any_changed = overlayfs_setup(enable);
268
269 if (any_changed) {
270 printf("Now reboot your device for settings to take effect\n");
271 }
272
273 return 0;
274 }
275