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 <getopt.h>
19 #include <stdio.h>
20 #include <sys/mount.h>
21 #include <sys/types.h>
22 #include <sys/vfs.h>
23 #include <unistd.h>
24
25 #include <string>
26 #include <thread>
27 #include <utility>
28 #include <vector>
29
30 #include <android-base/file.h>
31 #include <android-base/logging.h>
32 #include <android-base/properties.h>
33 #include <android-base/strings.h>
34 #include <android/os/IVold.h>
35 #include <binder/IServiceManager.h>
36 #include <bootloader_message/bootloader_message.h>
37 #include <cutils/android_reboot.h>
38 #include <fec/io.h>
39 #include <fs_mgr_overlayfs.h>
40 #include <fs_mgr_priv.h>
41 #include <fstab/fstab.h>
42 #include <libavb_user/libavb_user.h>
43 #include <libgsi/libgsid.h>
44
45 using namespace std::literals;
46
47 namespace {
48
usage(int exit_status)49 [[noreturn]] void usage(int exit_status) {
50 LOG(INFO) << getprogname()
51 << " [-h] [-R] [-T fstab_file] [partition]...\n"
52 "\t-h --help\tthis help\n"
53 "\t-R --reboot\tdisable verity & reboot to facilitate remount\n"
54 "\t-T --fstab\tcustom fstab file location\n"
55 "\tpartition\tspecific partition(s) (empty does all)\n"
56 "\n"
57 "Remount specified partition(s) read-write, by name or mount point.\n"
58 "-R notwithstanding, verity must be disabled on partition(s).\n"
59 "-R within a DSU guest system reboots into the DSU instead of the host system,\n"
60 "this command would enable DSU (one-shot) if not already enabled.";
61
62 ::exit(exit_status);
63 }
64
remountable_partition(const android::fs_mgr::FstabEntry & entry)65 bool remountable_partition(const android::fs_mgr::FstabEntry& entry) {
66 if (entry.fs_mgr_flags.vold_managed) return false;
67 if (entry.fs_mgr_flags.recovery_only) return false;
68 if (entry.fs_mgr_flags.slot_select_other) return false;
69 if (!(entry.flags & MS_RDONLY)) return false;
70 if (entry.fs_type == "vfat") return false;
71 return true;
72 }
73
system_mount_point(const android::fs_mgr::FstabEntry & entry)74 const std::string system_mount_point(const android::fs_mgr::FstabEntry& entry) {
75 if (entry.mount_point == "/") return "/system";
76 return entry.mount_point;
77 }
78
is_wrapped(const android::fs_mgr::Fstab & overlayfs_candidates,const android::fs_mgr::FstabEntry & entry)79 const android::fs_mgr::FstabEntry* is_wrapped(const android::fs_mgr::Fstab& overlayfs_candidates,
80 const android::fs_mgr::FstabEntry& entry) {
81 auto mount_point = system_mount_point(entry);
82 auto it = std::find_if(overlayfs_candidates.begin(), overlayfs_candidates.end(),
83 [&mount_point](const auto& entry) {
84 return android::base::StartsWith(mount_point,
85 system_mount_point(entry) + "/");
86 });
87 if (it == overlayfs_candidates.end()) return nullptr;
88 return &(*it);
89 }
90
91 auto verbose = false;
92
MyLogger(android::base::LogId id,android::base::LogSeverity severity,const char * tag,const char * file,unsigned int line,const char * message)93 void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
94 const char* file, unsigned int line, const char* message) {
95 if (verbose || severity == android::base::ERROR || message[0] != '[') {
96 fprintf(stderr, "%s\n", message);
97 }
98 static auto logd = android::base::LogdLogger();
99 logd(id, severity, tag, file, line, message);
100 }
101
reboot(bool overlayfs=false)102 [[noreturn]] void reboot(bool overlayfs = false) {
103 if (overlayfs) {
104 LOG(INFO) << "Successfully setup overlayfs\nrebooting device";
105 } else {
106 LOG(INFO) << "Successfully disabled verity\nrebooting device";
107 }
108 ::sync();
109 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,remount");
110 ::sleep(60);
111 ::exit(0); // SUCCESS
112 }
113
GetVold()114 static android::sp<android::os::IVold> GetVold() {
115 while (true) {
116 if (auto sm = android::defaultServiceManager()) {
117 if (auto binder = sm->getService(android::String16("vold"))) {
118 if (auto vold = android::interface_cast<android::os::IVold>(binder)) {
119 return vold;
120 }
121 }
122 }
123 std::this_thread::sleep_for(2s);
124 }
125 }
126
127 } // namespace
128
129 using namespace std::chrono_literals;
130
131 enum RemountStatus {
132 REMOUNT_SUCCESS = 0,
133 NOT_USERDEBUG,
134 BADARG,
135 NOT_ROOT,
136 NO_FSTAB,
137 UNKNOWN_PARTITION,
138 INVALID_PARTITION,
139 VERITY_PARTITION,
140 BAD_OVERLAY,
141 NO_MOUNTS,
142 REMOUNT_FAILED,
143 MUST_REBOOT,
144 BINDER_ERROR,
145 CHECKPOINTING,
146 GSID_ERROR,
147 CLEAN_SCRATCH_FILES,
148 };
149
do_remount(int argc,char * argv[])150 static int do_remount(int argc, char* argv[]) {
151 RemountStatus retval = REMOUNT_SUCCESS;
152
153 // If somehow this executable is delivered on a "user" build, it can
154 // not function, so providing a clear message to the caller rather than
155 // letting if fall through and provide a lot of confusing failure messages.
156 if (!ALLOW_ADBD_DISABLE_VERITY || (android::base::GetProperty("ro.debuggable", "0") != "1")) {
157 LOG(ERROR) << "only functions on userdebug or eng builds";
158 return NOT_USERDEBUG;
159 }
160
161 const char* fstab_file = nullptr;
162 auto can_reboot = false;
163
164 struct option longopts[] = {
165 {"fstab", required_argument, nullptr, 'T'},
166 {"help", no_argument, nullptr, 'h'},
167 {"reboot", no_argument, nullptr, 'R'},
168 {"verbose", no_argument, nullptr, 'v'},
169 {"clean_scratch_files", no_argument, nullptr, 'C'},
170 {0, 0, nullptr, 0},
171 };
172 for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
173 switch (opt) {
174 case 'h':
175 usage(SUCCESS);
176 break;
177 case 'R':
178 can_reboot = true;
179 break;
180 case 'T':
181 if (fstab_file) {
182 LOG(ERROR) << "Cannot supply two fstabs: -T " << fstab_file << " -T" << optarg;
183 usage(BADARG);
184 }
185 fstab_file = optarg;
186 break;
187 case 'v':
188 verbose = true;
189 break;
190 case 'C':
191 return CLEAN_SCRATCH_FILES;
192 default:
193 LOG(ERROR) << "Bad Argument -" << char(opt);
194 usage(BADARG);
195 break;
196 }
197 }
198
199 // Make sure we are root.
200 if (::getuid() != 0) {
201 LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
202 return NOT_ROOT;
203 }
204
205 // Read the selected fstab.
206 android::fs_mgr::Fstab fstab;
207 auto fstab_read = false;
208 if (fstab_file) {
209 fstab_read = android::fs_mgr::ReadFstabFromFile(fstab_file, &fstab);
210 } else {
211 fstab_read = android::fs_mgr::ReadDefaultFstab(&fstab);
212 // Manufacture a / entry from /proc/mounts if missing.
213 if (!GetEntryForMountPoint(&fstab, "/system") && !GetEntryForMountPoint(&fstab, "/")) {
214 android::fs_mgr::Fstab mounts;
215 if (android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
216 if (auto entry = GetEntryForMountPoint(&mounts, "/")) {
217 if (entry->fs_type != "rootfs") fstab.emplace_back(*entry);
218 }
219 }
220 }
221 }
222 if (!fstab_read || fstab.empty()) {
223 PLOG(ERROR) << "Failed to read fstab";
224 return NO_FSTAB;
225 }
226
227 if (android::base::GetBoolProperty("ro.virtual_ab.enabled", false) &&
228 !android::base::GetBoolProperty("ro.virtual_ab.retrofit", false)) {
229 // Virtual A/B devices can use /data as backing storage; make sure we're
230 // not checkpointing.
231 auto vold = GetVold();
232 bool checkpointing = false;
233 if (!vold->isCheckpointing(&checkpointing).isOk()) {
234 LOG(ERROR) << "Could not determine checkpointing status.";
235 return BINDER_ERROR;
236 }
237 if (checkpointing) {
238 LOG(ERROR) << "Cannot use remount when a checkpoint is in progress.";
239 return CHECKPOINTING;
240 }
241 }
242
243 // Generate the list of supported overlayfs mount points.
244 auto overlayfs_candidates = fs_mgr_overlayfs_candidate_list(fstab);
245
246 // Generate the all remountable partitions sub-list
247 android::fs_mgr::Fstab all;
248 for (auto const& entry : fstab) {
249 if (!remountable_partition(entry)) continue;
250 if (overlayfs_candidates.empty() ||
251 GetEntryForMountPoint(&overlayfs_candidates, entry.mount_point) ||
252 (is_wrapped(overlayfs_candidates, entry) == nullptr)) {
253 all.emplace_back(entry);
254 }
255 }
256
257 // Parse the unique list of valid partition arguments.
258 android::fs_mgr::Fstab partitions;
259 for (; argc > optind; ++optind) {
260 auto partition = std::string(argv[optind]);
261 if (partition.empty()) continue;
262 if (partition == "/") partition = "/system";
263 auto find_part = [&partition](const auto& entry) {
264 const auto mount_point = system_mount_point(entry);
265 if (partition == mount_point) return true;
266 if (partition == android::base::Basename(mount_point)) return true;
267 return false;
268 };
269 // Do we know about the partition?
270 auto it = std::find_if(fstab.begin(), fstab.end(), find_part);
271 if (it == fstab.end()) {
272 LOG(ERROR) << "Unknown partition " << argv[optind] << ", skipping";
273 retval = UNKNOWN_PARTITION;
274 continue;
275 }
276 // Is that one covered by an existing overlayfs?
277 auto wrap = is_wrapped(overlayfs_candidates, *it);
278 if (wrap) {
279 LOG(INFO) << "partition " << argv[optind] << " covered by overlayfs for "
280 << wrap->mount_point << ", switching";
281 partition = system_mount_point(*wrap);
282 }
283 // Is it a remountable partition?
284 it = std::find_if(all.begin(), all.end(), find_part);
285 if (it == all.end()) {
286 LOG(ERROR) << "Invalid partition " << argv[optind] << ", skipping";
287 retval = INVALID_PARTITION;
288 continue;
289 }
290 if (GetEntryForMountPoint(&partitions, it->mount_point) == nullptr) {
291 partitions.emplace_back(*it);
292 }
293 }
294
295 if (partitions.empty() && !retval) {
296 partitions = all;
297 }
298
299 // Check verity and optionally setup overlayfs backing.
300 auto reboot_later = false;
301 auto user_please_reboot_later = false;
302 auto setup_overlayfs = false;
303 auto just_disabled_verity = false;
304 for (auto it = partitions.begin(); it != partitions.end();) {
305 auto& entry = *it;
306 auto& mount_point = entry.mount_point;
307 if (fs_mgr_is_verity_enabled(entry)) {
308 retval = VERITY_PARTITION;
309 auto ret = false;
310 if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") != "locked") {
311 if (AvbOps* ops = avb_ops_user_new()) {
312 ret = avb_user_verity_set(
313 ops, android::base::GetProperty("ro.boot.slot_suffix", "").c_str(),
314 false);
315 avb_ops_user_free(ops);
316 }
317 if (!ret && fs_mgr_set_blk_ro(entry.blk_device, false)) {
318 fec::io fh(entry.blk_device.c_str(), O_RDWR);
319 ret = fh && fh.set_verity_status(false);
320 }
321 if (ret) {
322 LOG(WARNING) << "Disabling verity for " << mount_point;
323 just_disabled_verity = true;
324 reboot_later = can_reboot;
325 user_please_reboot_later = true;
326 }
327 }
328 if (!ret) {
329 LOG(ERROR) << "Skipping " << mount_point << " for remount";
330 it = partitions.erase(it);
331 continue;
332 }
333 }
334
335 auto change = false;
336 errno = 0;
337 if (fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change, just_disabled_verity)) {
338 if (change) {
339 LOG(INFO) << "Using overlayfs for " << mount_point;
340 reboot_later = can_reboot;
341 user_please_reboot_later = true;
342 setup_overlayfs = true;
343 }
344 } else if (errno) {
345 PLOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
346 retval = BAD_OVERLAY;
347 it = partitions.erase(it);
348 continue;
349 }
350 ++it;
351 }
352
353 // If (1) remount requires a reboot to take effect, (2) system is currently
354 // running a DSU guest and (3) DSU is disabled, then enable DSU so that the
355 // next reboot would not take us back to the host system but stay within
356 // the guest system.
357 if (reboot_later) {
358 if (auto gsid = android::gsi::GetGsiService()) {
359 auto dsu_running = false;
360 if (auto status = gsid->isGsiRunning(&dsu_running); !status.isOk()) {
361 LOG(ERROR) << "Failed to get DSU running state: " << status;
362 return BINDER_ERROR;
363 }
364 auto dsu_enabled = false;
365 if (auto status = gsid->isGsiEnabled(&dsu_enabled); !status.isOk()) {
366 LOG(ERROR) << "Failed to get DSU enabled state: " << status;
367 return BINDER_ERROR;
368 }
369 if (dsu_running && !dsu_enabled) {
370 std::string dsu_slot;
371 if (auto status = gsid->getActiveDsuSlot(&dsu_slot); !status.isOk()) {
372 LOG(ERROR) << "Failed to get active DSU slot: " << status;
373 return BINDER_ERROR;
374 }
375 LOG(INFO) << "DSU is running but disabled, enable DSU so that we stay within the "
376 "DSU guest system after reboot";
377 int error = 0;
378 if (auto status = gsid->enableGsi(/* oneShot = */ true, dsu_slot, &error);
379 !status.isOk() || error != android::gsi::IGsiService::INSTALL_OK) {
380 LOG(ERROR) << "Failed to enable DSU: " << status << ", error code: " << error;
381 return !status.isOk() ? BINDER_ERROR : GSID_ERROR;
382 }
383 LOG(INFO) << "Successfully enabled DSU (one-shot mode)";
384 }
385 }
386 }
387
388 if (partitions.empty() || just_disabled_verity) {
389 if (reboot_later) reboot(setup_overlayfs);
390 if (user_please_reboot_later) {
391 return MUST_REBOOT;
392 }
393 LOG(WARNING) << "No partitions to remount";
394 return retval;
395 }
396
397 // Mount overlayfs.
398 errno = 0;
399 if (!fs_mgr_overlayfs_mount_all(&partitions) && errno) {
400 retval = BAD_OVERLAY;
401 PLOG(ERROR) << "Can not mount overlayfs for partitions";
402 }
403
404 // Get actual mounts _after_ overlayfs has been added.
405 android::fs_mgr::Fstab mounts;
406 if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts) || mounts.empty()) {
407 PLOG(ERROR) << "Failed to read /proc/mounts";
408 retval = NO_MOUNTS;
409 }
410
411 // Remount selected partitions.
412 for (auto& entry : partitions) {
413 // unlock the r/o key for the mount point device
414 if (entry.fs_mgr_flags.logical) {
415 fs_mgr_update_logical_partition(&entry);
416 }
417 auto blk_device = entry.blk_device;
418 auto mount_point = entry.mount_point;
419
420 auto found = false;
421 for (auto it = mounts.rbegin(); it != mounts.rend(); ++it) {
422 auto& rentry = *it;
423 if (mount_point == rentry.mount_point) {
424 blk_device = rentry.blk_device;
425 found = true;
426 break;
427 }
428 // Find overlayfs mount point?
429 if ((mount_point == "/" && rentry.mount_point == "/system") ||
430 (mount_point == "/system" && rentry.mount_point == "/")) {
431 blk_device = rentry.blk_device;
432 mount_point = "/system";
433 found = true;
434 break;
435 }
436 }
437 if (!found) {
438 PLOG(INFO) << "skip unmounted partition dev:" << blk_device << " mnt:" << mount_point;
439 continue;
440 }
441 if (blk_device == "/dev/root") {
442 auto from_fstab = GetEntryForMountPoint(&fstab, mount_point);
443 if (from_fstab) blk_device = from_fstab->blk_device;
444 }
445 fs_mgr_set_blk_ro(blk_device, false);
446
447 // Find system-as-root mount point?
448 if ((mount_point == "/system") && !GetEntryForMountPoint(&mounts, mount_point) &&
449 GetEntryForMountPoint(&mounts, "/")) {
450 mount_point = "/";
451 }
452
453 // Now remount!
454 if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
455 nullptr) == 0) {
456 continue;
457 }
458 if ((errno == EINVAL) && (mount_point != entry.mount_point)) {
459 mount_point = entry.mount_point;
460 if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
461 nullptr) == 0) {
462 continue;
463 }
464 }
465 PLOG(ERROR) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point;
466 // If errno is EROFS at this point, we are dealing with r/o
467 // filesystem types like squashfs, erofs or ext4 dedupe. We will
468 // consider such a device that does not have CONFIG_OVERLAY_FS
469 // in the kernel as a misconfigured.
470 if (errno == EROFS) {
471 LOG(ERROR) << "Consider providing all the dependencies to enable overlayfs";
472 }
473 retval = REMOUNT_FAILED;
474 }
475
476 if (reboot_later) reboot(setup_overlayfs);
477 if (user_please_reboot_later) {
478 LOG(INFO) << "Now reboot your device for settings to take effect";
479 return 0;
480 }
481
482 return retval;
483 }
484
do_clean_scratch_files()485 static int do_clean_scratch_files() {
486 android::fs_mgr::CleanupOldScratchFiles();
487 return 0;
488 }
489
main(int argc,char * argv[])490 int main(int argc, char* argv[]) {
491 android::base::InitLogging(argv, MyLogger);
492 if (argc > 0 && android::base::Basename(argv[0]) == "clean_scratch_files"s) {
493 return do_clean_scratch_files();
494 }
495 int result = do_remount(argc, argv);
496 if (result == MUST_REBOOT) {
497 LOG(INFO) << "Now reboot your device for settings to take effect";
498 result = 0;
499 } else if (result == REMOUNT_SUCCESS) {
500 printf("remount succeeded\n");
501 } else if (result == CLEAN_SCRATCH_FILES) {
502 return do_clean_scratch_files();
503 } else {
504 printf("remount failed\n");
505 }
506 return result;
507 }
508