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