Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc00a09d authored by David Anderson's avatar David Anderson Committed by Gerrit Code Review
Browse files

Merge changes I1f104422,Iada733bc,I1428eed9

* changes:
  remount: Refactor remounting into a helper function.
  remount: Refactor dsu enabling into a helper function.
  remount: Refactor verity disabling into a helper function.
parents 830922a2 584fe256
Loading
Loading
Loading
Loading
+25 −20
Original line number Diff line number Diff line
@@ -85,6 +85,10 @@ bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) {

#if ALLOW_ADBD_DISABLE_VERITY == 0  // If we are a user build, provide stubs

bool fs_mgr_wants_overlayfs(FstabEntry*) {
    return false;
}

Fstab fs_mgr_overlayfs_candidate_list(const Fstab&) {
    return {};
}
@@ -388,26 +392,6 @@ bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overl
    return false;
}

bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
    // Don't check entries that are managed by vold.
    if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;

    // *_other doesn't want overlayfs.
    if (entry->fs_mgr_flags.slot_select_other) return false;

    // Only concerned with readonly partitions.
    if (!(entry->flags & MS_RDONLY)) return false;

    // If unbindable, do not allow overlayfs as this could expose us to
    // security issues.  On Android, this could also be used to turn off
    // the ability to overlay an otherwise acceptable filesystem since
    // /system and /vendor are never bound(sic) to.
    if (entry->flags & MS_UNBINDABLE) return false;

    if (!fs_mgr_overlayfs_enabled(entry)) return false;

    return true;
}
constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";

bool fs_mgr_overlayfs_setup_dir(const std::string& dir, std::string* overlay, bool* change) {
@@ -1284,6 +1268,27 @@ bool fs_mgr_overlayfs_invalid() {

}  // namespace

bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
    // Don't check entries that are managed by vold.
    if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;

    // *_other doesn't want overlayfs.
    if (entry->fs_mgr_flags.slot_select_other) return false;

    // Only concerned with readonly partitions.
    if (!(entry->flags & MS_RDONLY)) return false;

    // If unbindable, do not allow overlayfs as this could expose us to
    // security issues.  On Android, this could also be used to turn off
    // the ability to overlay an otherwise acceptable filesystem since
    // /system and /vendor are never bound(sic) to.
    if (entry->flags & MS_UNBINDABLE) return false;

    if (!fs_mgr_overlayfs_enabled(entry)) return false;

    return true;
}

Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) {
    Fstab candidates;
    for (const auto& entry : fstab) {
+178 −150
Original line number Diff line number Diff line
@@ -261,9 +261,168 @@ static RemountStatus GetRemountList(const Fstab& fstab, const std::vector<std::s
    return REMOUNT_SUCCESS;
}

static int do_remount(int argc, char* argv[]) {
    RemountStatus retval = REMOUNT_SUCCESS;
struct RemountCheckResult {
    bool reboot_later = false;
    bool setup_overlayfs = false;
    bool disabled_verity = false;
    bool verity_error = false;
};

static RemountStatus CheckVerity(const FstabEntry& entry, RemountCheckResult* result) {
    if (!fs_mgr_is_verity_enabled(entry)) {
        return REMOUNT_SUCCESS;
    }
    if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked") {
        return VERITY_PARTITION;
    }

    bool ok = false;

    std::unique_ptr<AvbOps, decltype(&::avb_ops_user_free)> ops(avb_ops_user_new(),
                                                                &::avb_ops_user_free);
    if (ops) {
        auto suffix = android::base::GetProperty("ro.boot.slot_suffix", "");
        ok = avb_user_verity_set(ops.get(), suffix.c_str(), false);
    }
    if (!ok && fs_mgr_set_blk_ro(entry.blk_device, false)) {
        fec::io fh(entry.blk_device.c_str(), O_RDWR);
        ok = fh && fh.set_verity_status(false);
    }
    if (!ok) {
        return VERITY_PARTITION;
    }
    result->disabled_verity = true;
    result->reboot_later = true;
    return REMOUNT_SUCCESS;
}

static RemountStatus CheckVerityAndOverlayfs(Fstab* partitions, RemountCheckResult* result) {
    RemountStatus status = REMOUNT_SUCCESS;
    for (auto it = partitions->begin(); it != partitions->end();) {
        auto& entry = *it;
        const auto& mount_point = entry.mount_point;

        if (auto rv = CheckVerity(entry, result); rv != REMOUNT_SUCCESS) {
            LOG(ERROR) << "Skipping verified partition " << mount_point << " for remount";
            status = rv;
            it = partitions->erase(it);
            continue;
        }

        if (fs_mgr_wants_overlayfs(&entry)) {
            bool change = false;
            bool force = result->disabled_verity;
            if (!fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change, force)) {
                LOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
                status = BAD_OVERLAY;
                it = partitions->erase(it);
                continue;
            }
            if (change) {
                LOG(INFO) << "Using overlayfs for " << mount_point;
                result->reboot_later = true;
                result->setup_overlayfs = true;
            }
        }
        it++;
    }
    return status;
}

static RemountStatus EnableDsuIfNeeded() {
    auto gsid = android::gsi::GetGsiService();
    if (!gsid) {
        return REMOUNT_SUCCESS;
    }

    auto dsu_running = false;
    if (auto status = gsid->isGsiRunning(&dsu_running); !status.isOk()) {
        LOG(ERROR) << "Failed to get DSU running state: " << status;
        return BINDER_ERROR;
    }
    auto dsu_enabled = false;
    if (auto status = gsid->isGsiEnabled(&dsu_enabled); !status.isOk()) {
        LOG(ERROR) << "Failed to get DSU enabled state: " << status;
        return BINDER_ERROR;
    }
    if (dsu_running && !dsu_enabled) {
        std::string dsu_slot;
        if (auto status = gsid->getActiveDsuSlot(&dsu_slot); !status.isOk()) {
            LOG(ERROR) << "Failed to get active DSU slot: " << status;
            return BINDER_ERROR;
        }
        LOG(INFO) << "DSU is running but disabled, enable DSU so that we stay within the "
                     "DSU guest system after reboot";
        int error = 0;
        if (auto status = gsid->enableGsi(/* oneShot = */ true, dsu_slot, &error);
            !status.isOk() || error != android::gsi::IGsiService::INSTALL_OK) {
            LOG(ERROR) << "Failed to enable DSU: " << status << ", error code: " << error;
            return !status.isOk() ? BINDER_ERROR : GSID_ERROR;
        }
        LOG(INFO) << "Successfully enabled DSU (one-shot mode)";
    }
    return REMOUNT_SUCCESS;
}

static RemountStatus RemountPartition(Fstab& fstab, Fstab& mounts, FstabEntry& entry) {
    // unlock the r/o key for the mount point device
    if (entry.fs_mgr_flags.logical) {
        fs_mgr_update_logical_partition(&entry);
    }
    auto blk_device = entry.blk_device;
    auto mount_point = entry.mount_point;

    auto found = false;
    for (auto it = mounts.rbegin(); it != mounts.rend(); ++it) {
        auto& rentry = *it;
        if (mount_point == rentry.mount_point) {
            blk_device = rentry.blk_device;
            found = true;
            break;
        }
        // Find overlayfs mount point?
        if ((mount_point == "/" && rentry.mount_point == "/system") ||
            (mount_point == "/system" && rentry.mount_point == "/")) {
            blk_device = rentry.blk_device;
            mount_point = "/system";
            found = true;
            break;
        }
    }
    if (!found) {
        PLOG(INFO) << "skip unmounted partition dev:" << blk_device << " mnt:" << mount_point;
        return REMOUNT_SUCCESS;
    }
    if (blk_device == "/dev/root") {
        auto from_fstab = GetEntryForMountPoint(&fstab, mount_point);
        if (from_fstab) blk_device = from_fstab->blk_device;
    }
    fs_mgr_set_blk_ro(blk_device, false);

    // Find system-as-root mount point?
    if ((mount_point == "/system") && !GetEntryForMountPoint(&mounts, mount_point) &&
        GetEntryForMountPoint(&mounts, "/")) {
        mount_point = "/";
    }

    // Now remount!
    if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
                nullptr) == 0) {
        return REMOUNT_SUCCESS;
    }
    if ((errno == EINVAL) && (mount_point != entry.mount_point)) {
        mount_point = entry.mount_point;
        if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
                    nullptr) == 0) {
            return REMOUNT_SUCCESS;
        }
    }

    PLOG(ERROR) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point;
    return REMOUNT_FAILED;
}

static int do_remount(int argc, char* argv[]) {
    // If somehow this executable is delivered on a "user" build, it can
    // not function, so providing a clear message to the caller rather than
    // letting if fall through and provide a lot of confusing failure messages.
@@ -342,97 +501,26 @@ static int do_remount(int argc, char* argv[]) {
    }

    // Check verity and optionally setup overlayfs backing.
    auto reboot_later = false;
    auto user_please_reboot_later = false;
    auto setup_overlayfs = false;
    auto just_disabled_verity = false;
    for (auto it = partitions.begin(); it != partitions.end();) {
        auto& entry = *it;
        auto& mount_point = entry.mount_point;
        if (fs_mgr_is_verity_enabled(entry)) {
            retval = VERITY_PARTITION;
            auto ret = false;
            if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") != "locked") {
                if (AvbOps* ops = avb_ops_user_new()) {
                    ret = avb_user_verity_set(
                            ops, android::base::GetProperty("ro.boot.slot_suffix", "").c_str(),
                            false);
                    avb_ops_user_free(ops);
                }
                if (!ret && fs_mgr_set_blk_ro(entry.blk_device, false)) {
                    fec::io fh(entry.blk_device.c_str(), O_RDWR);
                    ret = fh && fh.set_verity_status(false);
                }
                if (ret) {
                    LOG(WARNING) << "Disabling verity for " << mount_point;
                    just_disabled_verity = true;
                    reboot_later = can_reboot;
                    user_please_reboot_later = true;
                }
            }
            if (!ret) {
                LOG(ERROR) << "Skipping " << mount_point << " for remount";
                it = partitions.erase(it);
                continue;
            }
        }
    RemountCheckResult check_result;
    auto retval = CheckVerityAndOverlayfs(&partitions, &check_result);

        auto change = false;
        errno = 0;
        if (fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change, just_disabled_verity)) {
            if (change) {
                LOG(INFO) << "Using overlayfs for " << mount_point;
                reboot_later = can_reboot;
                user_please_reboot_later = true;
                setup_overlayfs = true;
            }
        } else if (errno) {
            PLOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
            retval = BAD_OVERLAY;
            it = partitions.erase(it);
            continue;
        }
        ++it;
    }
    bool auto_reboot = check_result.reboot_later && can_reboot;

    // If (1) remount requires a reboot to take effect, (2) system is currently
    // running a DSU guest and (3) DSU is disabled, then enable DSU so that the
    // next reboot would not take us back to the host system but stay within
    // the guest system.
    if (reboot_later) {
        if (auto gsid = android::gsi::GetGsiService()) {
            auto dsu_running = false;
            if (auto status = gsid->isGsiRunning(&dsu_running); !status.isOk()) {
                LOG(ERROR) << "Failed to get DSU running state: " << status;
                return BINDER_ERROR;
            }
            auto dsu_enabled = false;
            if (auto status = gsid->isGsiEnabled(&dsu_enabled); !status.isOk()) {
                LOG(ERROR) << "Failed to get DSU enabled state: " << status;
                return BINDER_ERROR;
            }
            if (dsu_running && !dsu_enabled) {
                std::string dsu_slot;
                if (auto status = gsid->getActiveDsuSlot(&dsu_slot); !status.isOk()) {
                    LOG(ERROR) << "Failed to get active DSU slot: " << status;
                    return BINDER_ERROR;
                }
                LOG(INFO) << "DSU is running but disabled, enable DSU so that we stay within the "
                             "DSU guest system after reboot";
                int error = 0;
                if (auto status = gsid->enableGsi(/* oneShot = */ true, dsu_slot, &error);
                    !status.isOk() || error != android::gsi::IGsiService::INSTALL_OK) {
                    LOG(ERROR) << "Failed to enable DSU: " << status << ", error code: " << error;
                    return !status.isOk() ? BINDER_ERROR : GSID_ERROR;
                }
                LOG(INFO) << "Successfully enabled DSU (one-shot mode)";
            }
    if (auto_reboot) {
        if (auto rv = EnableDsuIfNeeded(); rv != REMOUNT_SUCCESS) {
            return rv;
        }
    }

    if (partitions.empty() || just_disabled_verity) {
        if (reboot_later) reboot(setup_overlayfs);
        if (user_please_reboot_later) {
    if (partitions.empty() || check_result.disabled_verity) {
        if (auto_reboot) {
            reboot(check_result.setup_overlayfs);
        }
        if (check_result.reboot_later) {
            return MUST_REBOOT;
        }
        LOG(WARNING) << "No partitions to remount";
@@ -442,88 +530,28 @@ static int do_remount(int argc, char* argv[]) {
    // Mount overlayfs.
    errno = 0;
    if (!fs_mgr_overlayfs_mount_all(&partitions) && errno) {
        retval = BAD_OVERLAY;
        PLOG(ERROR) << "Can not mount overlayfs for partitions";
        return BAD_OVERLAY;
    }

    // Get actual mounts _after_ overlayfs has been added.
    android::fs_mgr::Fstab mounts;
    if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts) || mounts.empty()) {
        PLOG(ERROR) << "Failed to read /proc/mounts";
        retval = NO_MOUNTS;
        return NO_MOUNTS;
    }

    // Remount selected partitions.
    for (auto& entry : partitions) {
        // unlock the r/o key for the mount point device
        if (entry.fs_mgr_flags.logical) {
            fs_mgr_update_logical_partition(&entry);
        if (auto rv = RemountPartition(fstab, mounts, entry); rv != REMOUNT_SUCCESS) {
            retval = rv;
        }
        auto blk_device = entry.blk_device;
        auto mount_point = entry.mount_point;

        auto found = false;
        for (auto it = mounts.rbegin(); it != mounts.rend(); ++it) {
            auto& rentry = *it;
            if (mount_point == rentry.mount_point) {
                blk_device = rentry.blk_device;
                found = true;
                break;
            }
            // Find overlayfs mount point?
            if ((mount_point == "/" && rentry.mount_point == "/system")  ||
                (mount_point == "/system" && rentry.mount_point == "/")) {
                blk_device = rentry.blk_device;
                mount_point = "/system";
                found = true;
                break;
            }
        }
        if (!found) {
            PLOG(INFO) << "skip unmounted partition dev:" << blk_device << " mnt:" << mount_point;
            continue;
        }
        if (blk_device == "/dev/root") {
            auto from_fstab = GetEntryForMountPoint(&fstab, mount_point);
            if (from_fstab) blk_device = from_fstab->blk_device;
        }
        fs_mgr_set_blk_ro(blk_device, false);

        // Find system-as-root mount point?
        if ((mount_point == "/system") && !GetEntryForMountPoint(&mounts, mount_point) &&
            GetEntryForMountPoint(&mounts, "/")) {
            mount_point = "/";
        }

        // Now remount!
        if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
                    nullptr) == 0) {
            continue;
        }
        if ((errno == EINVAL) && (mount_point != entry.mount_point)) {
            mount_point = entry.mount_point;
            if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
                        nullptr) == 0) {
                continue;
            }
        }
        PLOG(ERROR) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point;
        // If errno is EROFS at this point, we are dealing with r/o
        // filesystem types like squashfs, erofs or ext4 dedupe. We will
        // consider such a device that does not have CONFIG_OVERLAY_FS
        // in the kernel as a misconfigured.
        if (errno == EROFS) {
            LOG(ERROR) << "Consider providing all the dependencies to enable overlayfs";
        }
        retval = REMOUNT_FAILED;
    }

    if (reboot_later) reboot(setup_overlayfs);
    if (user_please_reboot_later) {
    if (auto_reboot) reboot(check_result.setup_overlayfs);
    if (check_result.reboot_later) {
        LOG(INFO) << "Now reboot your device for settings to take effect";
        return 0;
    }

    return retval;
}

+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@

android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);

bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry);
bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab);
bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
                            bool* change = nullptr, bool force = true);