diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-13 20:37:40 +0000 |
---|---|---|
committer | Justin Dunlap <justindunlap@google.com> | 2022-05-16 22:57:33 +0000 |
commit | 8be6a2dc5e4aaf7208b3b3afc8d1ccf8c7956ade (patch) | |
tree | d747d209c55d053f6c62804e8eb1ee9d09b3a768 | |
parent | 3e199be0fcc31325bab3aea9ecd7808006b14e9d (diff) | |
parent | 8e921c62268e244813587211c1f99cd96283a5f0 (diff) | |
download | base-8be6a2dc5e4aaf7208b3b3afc8d1ccf8c7956ade.tar.gz |
Merge cherrypicks of [17415776, 17416378, 17416379, 17416380, 17416381, 17452585, 17823648, 17864291] into security-aosp-qt-release.android-security-10.0.0_r68
Change-Id: Ie2f709df5247eec094c7dc389529d6d5e1d93daa
7 files changed, 135 insertions, 6 deletions
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java index 1f6c3cc76ddd..674dcc024ddc 100644 --- a/core/java/android/os/UserManagerInternal.java +++ b/core/java/android/os/UserManagerInternal.java @@ -221,4 +221,12 @@ public abstract class UserManagerInternal { */ public abstract boolean isSettingRestrictedForUser(String setting, int userId, String value, int callingUid); + + /** + * Returns {@code true} if the system should ignore errors when preparing + * the storage directories for the user with ID {@code userId}. This will + * return {@code false} for all new users; it will only return {@code true} + * for users that already existed on-disk from an older version of Android. + */ + public abstract boolean shouldIgnorePrepareStorageErrors(int userId); } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index deff7ef7d39a..a252ba4452ea 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -117,6 +117,7 @@ import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.DataUnit; +import android.util.EventLog; import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -2848,7 +2849,21 @@ class StorageManagerService extends IStorageManager.Stub try { mVold.prepareUserStorage(volumeUuid, userId, serialNumber, flags); } catch (Exception e) { + EventLog.writeEvent(0x534e4554, "224585613", -1, ""); Slog.wtf(TAG, e); + // Make sure to re-throw this exception; we must not ignore failure + // to prepare the user storage as it could indicate that encryption + // wasn't successfully set up. + // + // Very unfortunately, these errors need to be ignored for broken + // users that already existed on-disk from older Android versions. + UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class); + if (umInternal.shouldIgnorePrepareStorageErrors(userId)) { + Slog.wtf(TAG, "ignoring error preparing storage for existing user " + userId + + "; device may be insecure!"); + return; + } + throw new RuntimeException(e); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f60e5ccbab1d..f370335e6a79 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4755,8 +4755,11 @@ public class NotificationManagerService extends SystemService { try { fixNotification(notification, pkg, userId); - } catch (NameNotFoundException e) { - Slog.e(TAG, "Cannot create a context for sending app", e); + } catch (Exception e) { + if (notification.isForegroundService()) { + throw new SecurityException("Invalid FGS notification", e); + } + Slog.e(TAG, "Cannot fix notification", e); return; } diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java index 045a295da965..95482d7c7f1a 100644 --- a/services/core/java/com/android/server/pm/UserDataPreparer.java +++ b/services/core/java/com/android/server/pm/UserDataPreparer.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.pm.UserInfo; import android.os.Environment; import android.os.FileUtils; +import android.os.RecoverySystem; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.os.SystemProperties; @@ -115,6 +116,16 @@ class UserDataPreparer { // Try one last time; if we fail again we're really in trouble prepareUserDataLI(volumeUuid, userId, userSerial, flags | StorageManager.FLAG_STORAGE_DE, false); + } else { + try { + Log.wtf(TAG, "prepareUserData failed for user " + userId, e); + if (userId == UserHandle.USER_SYSTEM) { + RecoverySystem.rebootPromptAndWipeUserData(mContext, + "prepareUserData failed for system user"); + } + } catch (IOException e2) { + throw new RuntimeException("error rebooting into recovery", e2); + } } } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 204f186f9e13..1f659d44178d 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -177,6 +177,8 @@ public class UserManagerService extends IUserManager.Stub { private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions"; private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL = "lastRequestQuietModeEnabledCall"; + private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS = + "ignorePrepareStorageErrors"; private static final String ATTR_KEY = "key"; private static final String ATTR_VALUE_TYPE = "type"; private static final String ATTR_MULTIPLE = "m"; @@ -274,6 +276,14 @@ public class UserManagerService extends IUserManager.Stub { private long mLastRequestQuietModeEnabledMillis; + /** + * {@code true} if the system should ignore errors when preparing the + * storage directories for this user. This is {@code false} for all new + * users; it will only be {@code true} for users that already existed + * on-disk from an older version of Android. + */ + private boolean mIgnorePrepareStorageErrors; + void setLastRequestQuietModeEnabledMillis(long millis) { mLastRequestQuietModeEnabledMillis = millis; } @@ -282,6 +292,14 @@ public class UserManagerService extends IUserManager.Stub { return mLastRequestQuietModeEnabledMillis; } + boolean getIgnorePrepareStorageErrors() { + return mIgnorePrepareStorageErrors; + } + + void setIgnorePrepareStorageErrors() { + mIgnorePrepareStorageErrors = true; + } + void clearSeedAccountData() { seedAccountName = null; seedAccountType = null; @@ -2376,6 +2394,10 @@ public class UserManagerService extends IUserManager.Stub { serializer.endTag(/* namespace */ null, TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL); } + serializer.startTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS); + serializer.text(String.valueOf(userData.getIgnorePrepareStorageErrors())); + serializer.endTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS); + serializer.endTag(null, TAG_USER); serializer.endDocument(); @@ -2484,6 +2506,7 @@ public class UserManagerService extends IUserManager.Stub { Bundle baseRestrictions = null; Bundle localRestrictions = null; Bundle globalRestrictions = null; + boolean ignorePrepareStorageErrors = true; // default is true for old users XmlPullParser parser = Xml.newPullParser(); parser.setInput(is, StandardCharsets.UTF_8.name()); @@ -2562,6 +2585,11 @@ public class UserManagerService extends IUserManager.Stub { if (type == XmlPullParser.TEXT) { lastRequestQuietModeEnabledTimestamp = Long.parseLong(parser.getText()); } + } else if (TAG_IGNORE_PREPARE_STORAGE_ERRORS.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + ignorePrepareStorageErrors = Boolean.parseBoolean(parser.getText()); + } } } } @@ -2587,6 +2615,9 @@ public class UserManagerService extends IUserManager.Stub { userData.persistSeedData = persistSeedData; userData.seedAccountOptions = seedAccountOptions; userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp); + if (ignorePrepareStorageErrors) { + userData.setIgnorePrepareStorageErrors(); + } synchronized (mRestrictionsLock) { if (baseRestrictions != null) { @@ -3758,6 +3789,9 @@ public class UserManagerService extends IUserManager.Stub { pw.println(); } } + + pw.println(" Ignore errors preparing storage: " + + userData.getIgnorePrepareStorageErrors()); } } pw.println(); @@ -4102,6 +4136,14 @@ public class UserManagerService extends IUserManager.Stub { return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId, value, callingUid); } + + @Override + public boolean shouldIgnorePrepareStorageErrors(int userId) { + synchronized (mUsersLock) { + UserData userData = mUsers.get(userId); + return userData != null && userData.getIgnorePrepareStorageErrors(); + } + } } /* Remove all the users except of the system one. */ diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index 72fc18937ece..64e245d8dbaf 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -28,12 +28,14 @@ import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.os.Process; import android.os.SystemClock; +import android.os.UserManagerInternal; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.AtomicFile; +import com.android.server.LocalServices; import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto; import java.io.File; @@ -74,6 +76,7 @@ class TaskSnapshotPersister { private final Object mLock = new Object(); private final DirectoryResolver mDirectoryResolver; private final float mReducedScale; + private final UserManagerInternal mUserManagerInternal; /** * The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was @@ -84,6 +87,9 @@ class TaskSnapshotPersister { TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) { mDirectoryResolver = resolver; + + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); + if (service.mLowRamTaskSnapshotsAndRecents) { // Use very low res snapshots if we are using Go version of recents. mReducedScale = LOW_RAM_RECENTS_REDUCED_SCALE; @@ -172,7 +178,7 @@ class TaskSnapshotPersister { return; } } - SystemClock.sleep(100); + SystemClock.sleep(DELAY_MS); } } @@ -218,7 +224,7 @@ class TaskSnapshotPersister { private boolean createDirectory(int userId) { final File dir = getDirectory(userId); - return dir.exists() || dir.mkdirs(); + return dir.exists() || dir.mkdir(); } private void deleteSnapshot(int taskId, int userId) { @@ -243,18 +249,26 @@ class TaskSnapshotPersister { android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); while (true) { WriteQueueItem next; + boolean isReadyToWrite = false; synchronized (mLock) { if (mPaused) { next = null; } else { next = mWriteQueue.poll(); if (next != null) { - next.onDequeuedLocked(); + if (next.isReady()) { + isReadyToWrite = true; + next.onDequeuedLocked(); + } else { + mWriteQueue.addLast(next); + } } } } if (next != null) { - next.write(); + if (isReadyToWrite) { + next.write(); + } SystemClock.sleep(DELAY_MS); } synchronized (mLock) { @@ -274,6 +288,13 @@ class TaskSnapshotPersister { }; private abstract class WriteQueueItem { + /** + * @return {@code true} if item is ready to have {@link WriteQueueItem#write} called + */ + boolean isReady() { + return true; + } + abstract void write(); /** @@ -313,6 +334,11 @@ class TaskSnapshotPersister { } @Override + boolean isReady() { + return mUserManagerInternal.isUserUnlocked(mUserId); + } + + @Override void write() { if (!createDirectory(mUserId)) { Slog.e(TAG, "Unable to create snapshot directory for user dir=" diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index e004cd3fb0c4..f25110f549df 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -23,6 +23,9 @@ import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.app.ActivityManager.TaskSnapshot; import android.content.ComponentName; import android.graphics.Canvas; @@ -32,9 +35,14 @@ import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.UserManager; +import android.os.UserManagerInternal; + +import com.android.server.LocalServices; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import java.io.File; @@ -50,10 +58,26 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { TaskSnapshotLoader mLoader; int mTestUserId; + @BeforeClass + public static void setUpOnce() { + final UserManagerInternal userManager = mock(UserManagerInternal.class); + LocalServices.addService(UserManagerInternal.class, userManager); + } + + @AfterClass + public static void tearDownOnce() { + LocalServices.removeServiceForTest(UserManagerInternal.class); + } + @Before public void setUp() { final UserManager um = UserManager.get(getInstrumentation().getTargetContext()); mTestUserId = um.getUserHandle(); + + final UserManagerInternal userManagerInternal = + LocalServices.getService(UserManagerInternal.class); + when(userManagerInternal.isUserUnlocked(mTestUserId)).thenReturn(true); + mPersister = new TaskSnapshotPersister(mWm, userId -> FILES_DIR); mLoader = new TaskSnapshotLoader(mPersister); mPersister.start(); |