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

Commit c785063d authored by Eric Biggers's avatar Eric Biggers
Browse files

Ignore errors preparing user storage for existing users

Unfortunately we can't rule out the existence of devices where the user
storage wasn't properly prepared, due to StorageManagerService
previously ignoring errors from mVold.prepareUserStorage, combined with
OEMs potentially creating files in per-user directories too early.  And
forcing these broken devices to be factory reset upon taking an OTA is
not currently considered to be acceptable.

One option is to only check for prepareUserStorage errors on devices
that launched with T or later.  However, this is a serious issue and it
would be strongly preferable to do more than that.

Therefore, this CL makes it so that errors are checked for all new
users, rather than all new devices.  A field ignorePrepareStorageErrors
is added to the user record; it is only ever set to true implicitly,
when reading a user record from disk that lacks this field.  This field
is used by StorageManagerService to decide whether to check for errors.

Bug: 164488924
Bug: 216025819
Test: Intentionally made a device affected by this issue by reverting
      the CLs that introduced the error checks, and changing vold to
      inject an error into prepareUserStorage.   Then, flashed a build
      with this CL without wiping userdata.  The device still boots, as
      expected, and the log shows that the error was intentionally
      ignored.  Tested that if a second user is added, the error is
      *not* ignored and the second user's storage is destroyed before it
      can be used.  Finally, wiped the device and verified that it won't
      boot up anymore, as expected since error checking is enabled for
      the system user in that case.
Change-Id: I9bdd1a4bf5b14542adb901f264a91d489115c89b
(cherry picked from commit 60d8318c)
Merged-In: I9bdd1a4bf5b14542adb901f264a91d489115c89b
parent 7172fa43
Loading
Loading
Loading
Loading
+10 −1
Original line number Original line Diff line number Diff line
@@ -3670,11 +3670,20 @@ class StorageManagerService extends IStorageManager.Stub
                    mInstaller.tryMountDataMirror(volumeUuid);
                    mInstaller.tryMountDataMirror(volumeUuid);
                }
                }
            }
            }
        } catch (RemoteException | Installer.InstallerException e) {
        } catch (Exception e) {
            Slog.wtf(TAG, e);
            Slog.wtf(TAG, e);
            // Make sure to re-throw this exception; we must not ignore failure
            // Make sure to re-throw this exception; we must not ignore failure
            // to prepare the user storage as it could indicate that encryption
            // to prepare the user storage as it could indicate that encryption
            // wasn't successfully set up.
            // 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);
            throw new RuntimeException(e);
        }
        }
    }
    }
+8 −0
Original line number Original line Diff line number Diff line
@@ -312,4 +312,12 @@ public abstract class UserManagerInternal {
     */
     */
    public abstract void setDefaultCrossProfileIntentFilters(
    public abstract void setDefaultCrossProfileIntentFilters(
            @UserIdInt int parentUserId, @UserIdInt int profileUserId);
            @UserIdInt int parentUserId, @UserIdInt int profileUserId);

    /**
     * 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);
}
}
+53 −0
Original line number Original line Diff line number Diff line
@@ -211,6 +211,8 @@ public class UserManagerService extends IUserManager.Stub {
    private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
    private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
    private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL =
    private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL =
            "lastRequestQuietModeEnabledCall";
            "lastRequestQuietModeEnabledCall";
    private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS =
            "ignorePrepareStorageErrors";
    private static final String ATTR_KEY = "key";
    private static final String ATTR_KEY = "key";
    private static final String ATTR_VALUE_TYPE = "type";
    private static final String ATTR_VALUE_TYPE = "type";
    private static final String ATTR_MULTIPLE = "m";
    private static final String ATTR_MULTIPLE = "m";
@@ -320,6 +322,14 @@ public class UserManagerService extends IUserManager.Stub {


        private long mLastRequestQuietModeEnabledMillis;
        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) {
        void setLastRequestQuietModeEnabledMillis(long millis) {
            mLastRequestQuietModeEnabledMillis = millis;
            mLastRequestQuietModeEnabledMillis = millis;
        }
        }
@@ -328,6 +338,25 @@ public class UserManagerService extends IUserManager.Stub {
            return mLastRequestQuietModeEnabledMillis;
            return mLastRequestQuietModeEnabledMillis;
        }
        }


        boolean getIgnorePrepareStorageErrors() {
            return mIgnorePrepareStorageErrors;
        }

        @SuppressWarnings("AndroidFrameworkCompatChange")  // This is not an app-visible API.
        void setIgnorePrepareStorageErrors() {
            // This method won't be called for new users.  But to fully rule out
            // the possibility of mIgnorePrepareStorageErrors ever being true
            // for any user on any device that launched with T or later, we also
            // explicitly check that DEVICE_INITIAL_SDK_INT is below T before
            // honoring the request to set mIgnorePrepareStorageErrors to true.
            if (Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.TIRAMISU) {
                mIgnorePrepareStorageErrors = true;
                return;
            }
            Slog.w(LOG_TAG, "Not setting mIgnorePrepareStorageErrors to true"
                    + " since this is a new device");
        }

        void clearSeedAccountData() {
        void clearSeedAccountData() {
            seedAccountName = null;
            seedAccountName = null;
            seedAccountType = null;
            seedAccountType = null;
@@ -3408,6 +3437,10 @@ public class UserManagerService extends IUserManager.Stub {
            serializer.endTag(/* namespace */ null, TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL);
            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.endTag(null, TAG_USER);


        serializer.endDocument();
        serializer.endDocument();
@@ -3517,6 +3550,7 @@ public class UserManagerService extends IUserManager.Stub {
        Bundle legacyLocalRestrictions = null;
        Bundle legacyLocalRestrictions = null;
        RestrictionsSet localRestrictions = null;
        RestrictionsSet localRestrictions = null;
        Bundle globalRestrictions = null;
        Bundle globalRestrictions = null;
        boolean ignorePrepareStorageErrors = true; // default is true for old users


        final TypedXmlPullParser parser = Xml.resolvePullParser(is);
        final TypedXmlPullParser parser = Xml.resolvePullParser(is);
        int type;
        int type;
@@ -3595,6 +3629,11 @@ public class UserManagerService extends IUserManager.Stub {
                    if (type == XmlPullParser.TEXT) {
                    if (type == XmlPullParser.TEXT) {
                        lastRequestQuietModeEnabledTimestamp = Long.parseLong(parser.getText());
                        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());
                    }
                }
                }
            }
            }
        }
        }
@@ -3622,6 +3661,9 @@ public class UserManagerService extends IUserManager.Stub {
        userData.persistSeedData = persistSeedData;
        userData.persistSeedData = persistSeedData;
        userData.seedAccountOptions = seedAccountOptions;
        userData.seedAccountOptions = seedAccountOptions;
        userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
        userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
        if (ignorePrepareStorageErrors) {
            userData.setIgnorePrepareStorageErrors();
        }


        synchronized (mRestrictionsLock) {
        synchronized (mRestrictionsLock) {
            if (baseRestrictions != null) {
            if (baseRestrictions != null) {
@@ -5732,6 +5774,9 @@ public class UserManagerService extends IUserManager.Stub {
                pw.println();
                pw.println();
            }
            }
        }
        }

        pw.println("    Ignore errors preparing storage: "
                + userData.getIgnorePrepareStorageErrors());
    }
    }


    private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) {
    private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) {
@@ -6135,6 +6180,14 @@ public class UserManagerService extends IUserManager.Stub {
            UserManagerService.this.setDefaultCrossProfileIntentFilters(
            UserManagerService.this.setDefaultCrossProfileIntentFilters(
                    profileUserId, userTypeDetails, restrictions, parentUserId);
                    profileUserId, userTypeDetails, restrictions, parentUserId);
        }
        }

        @Override
        public boolean shouldIgnorePrepareStorageErrors(int userId) {
            synchronized (mUsersLock) {
                UserData userData = mUsers.get(userId);
                return userData != null && userData.getIgnorePrepareStorageErrors();
            }
        }
    }
    }


    /**
    /**