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

Unverified Commit 6ae97139 authored by Kevin F. Haggerty's avatar Kevin F. Haggerty
Browse files

Merge tag 'android-security-13.0.0_r16' into staging/lineage-20.0_android-security-13.0.0_r16

Android Security 13.0.0 Release 16 (11422632)

* tag 'android-security-13.0.0_r16':
  Fix security vulnerability that creates user with no restrictions when accountOptions are too long.
  Stop marking apps as privileged if they are not signed properly.
  isUserInLockDown can be true when there are other strong auth requirements
  Don't store invalid pkgs when migrating filters
  RESTRICT AUTOMERGE Added limitations for attributions to handle invalid cases

Conflicts:
	core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java

Change-Id: Ifa3cacd5f9966feb7185837867a1e4602ba14f11
parents 837a9d27 3772a875
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -294,6 +294,43 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
        XmlUtils.writeMapXml(mMap, out, this);
    }

    /**
     * Checks whether all keys and values are within the given character limit.
     * Note: Maximum character limit of String that can be saved to XML as part of bundle is 65535.
     * Otherwise IOException is thrown.
     * @param limit length of String keys and values in the PersistableBundle, including nested
     *                    PersistableBundles to check against.
     *
     * @hide
     */
    public boolean isBundleContentsWithinLengthLimit(int limit) {
        unparcel();
        if (mMap == null) {
            return true;
        }
        for (int i = 0; i < mMap.size(); i++) {
            if (mMap.keyAt(i) != null && mMap.keyAt(i).length() > limit) {
                return false;
            }
            final Object value = mMap.valueAt(i);
            if (value instanceof String && ((String) value).length() > limit) {
                return false;
            } else if (value instanceof String[]) {
                String[] stringArray =  (String[]) value;
                for (int j = 0; j < stringArray.length; j++) {
                    if (stringArray[j] != null
                            && stringArray[j].length() > limit) {
                        return false;
                    }
                }
            } else if (value instanceof PersistableBundle
                    && !((PersistableBundle) value).isBundleContentsWithinLengthLimit(limit)) {
                return false;
            }
        }
        return true;
    }

    /** @hide */
    static class MyReadMapCallback implements  XmlUtils.ReadMapCallback {
        @Override
+19 −4
Original line number Diff line number Diff line
@@ -100,6 +100,21 @@ public class UserManager {
    /** The userType of UserHandle.myUserId(); empty string if not a profile; null until cached. */
    private String mProfileTypeOfProcessUser = null;

    /** Maximum length of username.
     * @hide
     */
    public static final int MAX_USER_NAME_LENGTH = 100;

    /** Maximum length of user property String value.
     * @hide
     */
    public static final int MAX_ACCOUNT_STRING_LENGTH = 500;

    /** Maximum length of account options String values.
     * @hide
     */
    public static final int MAX_ACCOUNT_OPTIONS_LENGTH = 1000;

    /**
     * User type representing a {@link UserHandle#USER_SYSTEM system} user that is a human user.
     * This type of user cannot be created; it can only pre-exist on first boot.
@@ -3630,15 +3645,15 @@ public class UserManager {
     * time, the preferred user name and account information are used by the setup process for that
     * user.
     *
     * @param userName Optional name to assign to the user.
     * @param userName Optional name to assign to the user. Character limit is 100.
     * @param accountName Optional account name that will be used by the setup wizard to initialize
     *                    the user.
     *                    the user. Character limit is 500.
     * @param accountType Optional account type for the account to be created. This is required
     *                    if the account name is specified.
     *                    if the account name is specified. Character limit is 500.
     * @param accountOptions Optional bundle of data to be passed in during account creation in the
     *                       new user via {@link AccountManager#addAccount(String, String, String[],
     *                       Bundle, android.app.Activity, android.accounts.AccountManagerCallback,
     *                       Handler)}.
     *                       Handler)}. Character limit is 1000.
     * @return An Intent that can be launched from an Activity.
     * @see #USER_CREATION_FAILED_NOT_PERMITTED
     * @see #USER_CREATION_FAILED_NO_MORE_USERS
+12 −0
Original line number Diff line number Diff line
@@ -114,6 +114,14 @@ public class ConfirmUserCreationActivity extends AlertActivity
        if (cantCreateUser) {
            setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED);
            return null;
        } else if (!(isUserPropertyWithinLimit(mUserName, UserManager.MAX_USER_NAME_LENGTH)
                && isUserPropertyWithinLimit(mAccountName, UserManager.MAX_ACCOUNT_STRING_LENGTH)
                && isUserPropertyWithinLimit(mAccountType, UserManager.MAX_ACCOUNT_STRING_LENGTH))
                || (mAccountOptions != null && !mAccountOptions.isBundleContentsWithinLengthLimit(
                UserManager.MAX_ACCOUNT_OPTIONS_LENGTH))) {
            setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED);
            Log.i(TAG, "User properties must not exceed their character limits");
            return null;
        } else if (cantCreateAnyMoreUsers) {
            setResult(UserManager.USER_CREATION_FAILED_NO_MORE_USERS);
            return null;
@@ -141,4 +149,8 @@ public class ConfirmUserCreationActivity extends AlertActivity
        }
        finish();
    }

    private boolean isUserPropertyWithinLimit(String property, int limit) {
        return property == null || property.length() <= limit;
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -1367,8 +1367,8 @@ public class LockPatternUtils {
    }

    public boolean isUserInLockdown(int userId) {
        return getStrongAuthForUser(userId)
                == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
        return (getStrongAuthForUser(userId)
                & StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0;
    }

    private static class WrappedCallback extends ICheckCredentialProgressCallback.Stub {
+34 −5
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;

import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;

import static com.google.common.truth.Truth.assertThat;

@@ -70,12 +72,15 @@ import java.util.List;
@SmallTest
public class LockPatternUtilsTest {

    private ILockSettings mLockSettings;
    private static final int USER_ID = 1;
    private static final int DEMO_USER_ID = 5;

    private LockPatternUtils mLockPatternUtils;

    private void configureTest(boolean isSecure, boolean isDemoUser, int deviceDemoMode)
            throws Exception {
        mLockSettings = Mockito.mock(ILockSettings.class);
        final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));

        final MockContentResolver cr = new MockContentResolver(context);
@@ -83,15 +88,14 @@ public class LockPatternUtilsTest {
        when(context.getContentResolver()).thenReturn(cr);
        Settings.Global.putInt(cr, Settings.Global.DEVICE_DEMO_MODE, deviceDemoMode);

        final ILockSettings ils = Mockito.mock(ILockSettings.class);
        when(ils.getCredentialType(DEMO_USER_ID)).thenReturn(
        when(mLockSettings.getCredentialType(DEMO_USER_ID)).thenReturn(
                isSecure ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
                         : LockPatternUtils.CREDENTIAL_TYPE_NONE);
        when(ils.getLong("lockscreen.password_type", PASSWORD_QUALITY_UNSPECIFIED, DEMO_USER_ID))
                .thenReturn((long) PASSWORD_QUALITY_MANAGED);
        when(mLockSettings.getLong("lockscreen.password_type", PASSWORD_QUALITY_UNSPECIFIED,
                DEMO_USER_ID)).thenReturn((long) PASSWORD_QUALITY_MANAGED);
        // TODO(b/63758238): stop spying the class under test
        mLockPatternUtils = spy(new LockPatternUtils(context));
        when(mLockPatternUtils.getLockSettings()).thenReturn(ils);
        when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings);
        doReturn(true).when(mLockPatternUtils).hasSecureLockScreen();

        final UserInfo userInfo = Mockito.mock(UserInfo.class);
@@ -101,6 +105,31 @@ public class LockPatternUtilsTest {
        when(context.getSystemService(Context.USER_SERVICE)).thenReturn(um);
    }

    @Test
    public void isUserInLockDown() throws Exception {
        configureTest(true, false, 2);

        // GIVEN strong auth not required
        when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn(STRONG_AUTH_NOT_REQUIRED);

        // THEN user isn't in lockdown
        assertFalse(mLockPatternUtils.isUserInLockdown(USER_ID));

        // GIVEN lockdown
        when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn(
                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);

        // THEN user is in lockdown
        assertTrue(mLockPatternUtils.isUserInLockdown(USER_ID));

        // GIVEN lockdown and lockout
        when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn(
                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN | STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);

        // THEN user is in lockdown
        assertTrue(mLockPatternUtils.isUserInLockdown(USER_ID));
    }

    @Test
    public void isLockScreenDisabled_isDemoUser_true() throws Exception {
        configureTest(false, true, 2);
Loading