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

Commit 1a67da88 authored by Joël Stemmer's avatar Joël Stemmer
Browse files

Avoid entering an infinite loop in PackageManagerBackupAgent#onRestore

When the PackageManagerBackupAgent restores an old backup that does not
have an ancestral record version and the backup contains a package that
does not have any signatures it will enter an infinite loop. This
happens because it calls `continue` without reading the next key/value
pair in the backup.

Test: atest PackageManagerBackupAgentTest
Bug: 330708733
Change-Id: Ifb71293b75ccb68dc7e721593f04128417360491
parent 0c43ad7b
Loading
Loading
Loading
Loading
+8 −8
Original line number Original line Diff line number Diff line
@@ -781,6 +781,9 @@ public class PackageManagerBackupAgent extends BackupAgent {
                                "Not restoring package "
                                "Not restoring package "
                                        + key
                                        + key
                                        + " since it appears to have no signatures.");
                                        + " since it appears to have no signatures.");
                        if (!data.readNextHeader()) {
                            break;
                        }
                        continue;
                        continue;
                    }
                    }


@@ -790,18 +793,15 @@ public class PackageManagerBackupAgent extends BackupAgent {
                    sigMap.put(key, new Metadata(versionCode, sigs));
                    sigMap.put(key, new Metadata(versionCode, sigs));
                }
                }


                boolean readNextHeader = data.readNextHeader();
                if (!data.readNextHeader()) {
                if (!readNextHeader) {
                    if (DEBUG) {
                        Slog.v(
                                TAG,
                                "LegacyRestoreDataConsumer:"
                                        + " we're done reading all the headers");
                    }
                    break;
                    break;
                }
                }
            }
            }


            if (DEBUG) {
                Slog.v(TAG, "LegacyRestoreDataConsumer:" + " we're done reading all the headers");
            }

            // On successful completion, cache the signature map for the Backup Manager to use
            // On successful completion, cache the signature map for the Backup Manager to use
            mRestoredSignatures = sigMap;
            mRestoredSignatures = sigMap;
        }
        }
+24 −0
Original line number Original line Diff line number Diff line
@@ -211,6 +211,30 @@ public class PackageManagerBackupAgentTest {
        assertThat(mNewState.length()).isEqualTo(0);
        assertThat(mNewState.length()).isEqualTo(0);
    }
    }


    @Test
    public void onRestore_legacyBackupWithMissingSignature_restoresBackup() throws Exception {
        PackageInfo pkgWithoutSigs = createPackage("pkg.no.sigs", 1);
        pkgWithoutSigs.signingInfo =
                new SigningInfo(new SigningDetails(new Signature[0], 1, null, null));
        when(mPackageManager.getPackageInfoAsUser(
                        eq(pkgWithoutSigs.packageName), anyInt(), anyInt()))
                .thenReturn(pkgWithoutSigs);
        ImmutableList<PackageInfo> packages =
                ImmutableList.<PackageInfo>builder().addAll(mPackages).add(pkgWithoutSigs).build();
        mPackageManagerBackupAgent =
                new PackageManagerBackupAgent(mPackageManager, packages, USER_ID);
        // A legacy backup is one without an ancestral record version. Ancestral record versions
        // are always written however, so we'll need to delete it from the backup data before
        // restoring.
        runBackupAgentOnBackup();
        deleteKeyFromBackupData(mBackupData, PackageManagerBackupAgent.ANCESTRAL_RECORD_KEY);

        runBackupAgentOnRestore(); // should not fail or timeout

        assertThat(mPackageManagerBackupAgent.getRestoredPackages())
                .containsExactly(EXISTING_PACKAGE_NAME);
    }

    private void runBackupAgentOnBackup() throws Exception {
    private void runBackupAgentOnBackup() throws Exception {
        try (ParcelFileDescriptor oldStateDescriptor = openForReading(mOldState);
        try (ParcelFileDescriptor oldStateDescriptor = openForReading(mOldState);
                ParcelFileDescriptor backupDataDescriptor = openForWriting(mBackupData);
                ParcelFileDescriptor backupDataDescriptor = openForWriting(mBackupData);