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

Commit 9ca9303b authored by Daniel Rosenberg's avatar Daniel Rosenberg
Browse files

Format if Encryption was Interrupted

If we're partially through setting up metadata encryption, failures
leave the partition in a known bad state, and we can avoid an eventual
boot into recovery by taking the format path.

Bug: 351704691
Test: Inserted debug code to reboot during initial encryption setup
      Verified device boots successfully on second attempt
Change-Id: I2d8591fa68ab0656e42b7b12f69001a5897e1a61
parent 69c7daf1
Loading
Loading
Loading
Loading
+33 −9
Original line number Diff line number Diff line
@@ -930,7 +930,8 @@ static bool should_use_metadata_encryption(const FstabEntry& entry) {
// attempted_idx: On return, will indicate which fstab entry
//     succeeded. In case of failure, it will be the start_idx.
// Sets errno to match the 1st mount failure on failure.
static bool mount_with_alternatives(Fstab& fstab, int start_idx, int* end_idx, int* attempted_idx) {
static bool mount_with_alternatives(Fstab& fstab, int start_idx, bool interrupted, int* end_idx,
                                    int* attempted_idx) {
    unsigned long i;
    int mount_errno = 0;
    bool mounted = false;
@@ -949,6 +950,13 @@ static bool mount_with_alternatives(Fstab& fstab, int start_idx, int* end_idx, i
            continue;
        }

        if (interrupted) {
            LINFO << __FUNCTION__ << "(): skipping fstab mountpoint=" << fstab[i].mount_point
                  << " rec[" << i << "].fs_type=" << fstab[i].fs_type
                  << " (previously interrupted during encryption step)";
            continue;
        }

        // fstab[start_idx].blk_device is already updated to /dev/dm-<N> by
        // AVB related functions. Copy it from start_idx to the current index i.
        if ((i != start_idx) && fstab[i].fs_mgr_flags.logical &&
@@ -1416,6 +1424,15 @@ static bool IsMountPointMounted(const std::string& mount_point) {
    return GetEntryForMountPoint(&fstab, mount_point) != nullptr;
}

std::string fs_mgr_metadata_encryption_in_progress_file_name(const FstabEntry& entry) {
    return entry.metadata_key_dir + "/in_progress";
}

bool WasMetadataEncryptionInterrupted(const FstabEntry& entry) {
    if (!should_use_metadata_encryption(entry)) return false;
    return access(fs_mgr_metadata_encryption_in_progress_file_name(entry).c_str(), R_OK) == 0;
}

// When multiple fstab records share the same mount_point, it will try to mount each
// one in turn, and ignore any duplicates after a first successful mount.
// Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
@@ -1530,7 +1547,9 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
        int top_idx = i;
        int attempted_idx = -1;

        bool mret = mount_with_alternatives(*fstab, i, &last_idx_inspected, &attempted_idx);
        bool encryption_interrupted = WasMetadataEncryptionInterrupted(current_entry);
        bool mret = mount_with_alternatives(*fstab, i, encryption_interrupted, &last_idx_inspected,
                                            &attempted_idx);
        auto& attempted_entry = (*fstab)[attempted_idx];
        i = last_idx_inspected;
        int mount_errno = errno;
@@ -1579,13 +1598,18 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
        // Mounting failed, understand why and retry.
        wiped = partition_wiped(current_entry.blk_device.c_str());
        if (mount_errno != EBUSY && mount_errno != EACCES &&
            current_entry.fs_mgr_flags.formattable && wiped) {
            current_entry.fs_mgr_flags.formattable && (wiped || encryption_interrupted)) {
            // current_entry and attempted_entry point at the same partition, but sometimes
            // at two different lines in the fstab.  Use current_entry for formatting
            // as that is the preferred one.
            if (wiped)
                LERROR << __FUNCTION__ << "(): " << realpath(current_entry.blk_device)
                   << " is wiped and " << current_entry.mount_point << " " << current_entry.fs_type
                   << " is formattable. Format it.";
                       << " is wiped and " << current_entry.mount_point << " "
                       << current_entry.fs_type << " is formattable. Format it.";
            if (encryption_interrupted)
                LERROR << __FUNCTION__ << "(): " << realpath(current_entry.blk_device)
                       << " was interrupted during encryption and " << current_entry.mount_point
                       << " " << current_entry.fs_type << " is formattable. Format it.";

            checkpoint_manager.Revert(&current_entry);

@@ -1625,7 +1649,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
        }

        // mount(2) returned an error, handle the encryptable/formattable case.
        if (mount_errno != EBUSY && mount_errno != EACCES &&
        if (mount_errno != EBUSY && mount_errno != EACCES && !encryption_interrupted &&
            should_use_metadata_encryption(attempted_entry)) {
            if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.blk_device,
                           attempted_entry.mount_point,
@@ -1643,13 +1667,13 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
            // Use StringPrintf to output "(null)" instead.
            if (attempted_entry.fs_mgr_flags.no_fail) {
                PERROR << android::base::StringPrintf(
                        "Ignoring failure to mount an un-encryptable or wiped "
                        "Ignoring failure to mount an un-encryptable, interrupted, or wiped "
                        "partition on %s at %s options: %s",
                        attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(),
                        attempted_entry.fs_options.c_str());
            } else {
                PERROR << android::base::StringPrintf(
                        "Failed to mount an un-encryptable or wiped partition "
                        "Failed to mount an un-encryptable, interrupted, or wiped partition "
                        "on %s at %s options: %s",
                        attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(),
                        attempted_entry.fs_options.c_str());
+4 −0
Original line number Diff line number Diff line
@@ -144,3 +144,7 @@ bool fs_mgr_create_canonical_mount_point(const std::string& mount_point);
// Unlike fs_mgr_overlayfs, mount overlayfs without upperdir and workdir, so the
// filesystem cannot be remount read-write.
bool fs_mgr_mount_overlayfs_fstab_entry(const android::fs_mgr::FstabEntry& entry);

// File name used to track if encryption was interrupted, leading to a known bad fs state
std::string fs_mgr_metadata_encryption_in_progress_file_name(
        const android::fs_mgr::FstabEntry& entry);