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

Commit 30c88f6f authored by Josh Hou's avatar Josh Hou Committed by Automerger Merge Worker
Browse files

Fix the security vulnerability issue in AppLocalePickerActivity am: 33ef8379

parents d3054dcb 33ef8379
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settings.localepicker;
import android.app.FragmentTransaction;
import android.app.LocaleManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.LocaleList;
@@ -34,6 +35,7 @@ import com.android.internal.app.LocalePickerWithRegion;
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppLocaleUtil;
import com.android.settings.applications.appinfo.AppLocaleDetails;
import com.android.settings.core.SettingsBaseActivity;

@@ -64,12 +66,17 @@ public class AppLocalePickerActivity extends SettingsBaseActivity
        }
        mContextAsUser = this;
        if (getIntent().hasExtra(AppInfoBase.ARG_PACKAGE_UID)) {
            int userId = getIntent().getIntExtra(AppInfoBase.ARG_PACKAGE_UID, -1);
            if (userId != -1) {
                UserHandle userHandle = UserHandle.getUserHandleForUid(userId);
            int uid = getIntent().getIntExtra(AppInfoBase.ARG_PACKAGE_UID, -1);
            if (uid != -1) {
                UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
                mContextAsUser = createContextAsUser(userHandle, 0);
            }
        }
        if (!canDisplayLocaleUi() || mContextAsUser.getUserId() != UserHandle.myUserId()) {
            Log.w(TAG, "Not allow to display Locale Settings UI.");
            finish();
            return;
        }

        setTitle(R.string.app_locale_picker_title);
        getActionBar().setDisplayHomeAsUpEnabled(true);
@@ -160,4 +167,10 @@ public class AppLocalePickerActivity extends SettingsBaseActivity
                .replace(R.id.content_frame, mLocalePickerWithRegion)
                .commit();
    }

    private boolean canDisplayLocaleUi() {
        return AppLocaleUtil.canDisplayLocaleUi(mContextAsUser, mPackageName,
                mContextAsUser.getPackageManager().queryIntentActivities(
                        AppLocaleUtil.LAUNCHER_ENTRY_INTENT, PackageManager.GET_META_DATA));
    }
}
+167 −5
Original line number Diff line number Diff line
@@ -18,25 +18,35 @@ package com.android.settings.localepicker;

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

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.annotation.Nullable;
import android.app.Activity;
import android.app.ApplicationPackageManager;
import android.app.LocaleConfig;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.net.Uri;
import android.os.LocaleList;
import android.os.Process;
import android.os.UserHandle;
import android.telephony.TelephonyManager;

import androidx.annotation.ArrayRes;

import com.android.internal.app.LocaleStore;
import com.android.settings.applications.AppInfoBase;

import java.util.Locale;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,17 +55,26 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowPackageManager;
import org.robolectric.shadows.ShadowTelephonyManager;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

@RunWith(RobolectricTestRunner.class)
@Config(
        shadows = {
                AppLocalePickerActivityTest.ShadowApplicationPackageManager.class,
                AppLocalePickerActivityTest.ShadowResources.class,
                AppLocalePickerActivityTest.ShadowUserHandle.class,
                AppLocalePickerActivityTest.ShadowLocaleConfig.class,
        })
public class AppLocalePickerActivityTest {
    private static final String TEST_PACKAGE_NAME = "com.android.settings";
@@ -67,21 +86,99 @@ public class AppLocalePickerActivityTest {
    @Rule
    public MockitoRule rule = MockitoJUnit.rule();

    private Context mContext;
    private ShadowPackageManager mPackageManager;

    @Before
    public void setUp() {
        mContext = spy(RuntimeEnvironment.application);
        mPackageManager = Shadows.shadowOf(mContext.getPackageManager());
    }

    @After
    public void tearDown() {
        mPackageManager.removePackage(TEST_PACKAGE_NAME);
        ShadowResources.setDisAllowPackage(false);
        ShadowApplicationPackageManager.setNoLaunchEntry(false);
        ShadowUserHandle.setUserId(0);
        ShadowLocaleConfig.setStatus(LocaleConfig.STATUS_SUCCESS);
    }

    @Test
    public void launchAppLocalePickerActivity_hasPackageName_success() {
        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);

        controller.create();

        assertThat(controller.get().isFinishing()).isFalse();
    }

    @Test
    public void launchAppLocalePickerActivity_appNoLocaleConfig_failed() {
        ShadowLocaleConfig.setStatus(LocaleConfig.STATUS_NOT_SPECIFIED);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_appSignPlatformKey_failed() {
        final ApplicationInfo applicationInfo = new ApplicationInfo();
        applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
        applicationInfo.packageName = TEST_PACKAGE_NAME;

        final PackageInfo packageInfo = new PackageInfo();
        packageInfo.packageName = TEST_PACKAGE_NAME;
        packageInfo.applicationInfo = applicationInfo;
        mPackageManager.installPackage(packageInfo);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_appMatchDisallowedPackage_failed() {
        ShadowResources.setDisAllowPackage(true);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_appNoLaunchEntry_failed() {
        ShadowApplicationPackageManager.setNoLaunchEntry(true);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_modifyAppLocalesOfAnotherUser_failed() {
        ShadowUserHandle.setUserId(10);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_intentWithoutPackageName_failed() {
        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(false);

        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
@@ -125,7 +222,7 @@ public class AppLocalePickerActivityTest {
        if (hasPackageName) {
            data.setData(TEST_PACKAGE_URI);
        }
        data.putExtra(AppInfoBase.ARG_PACKAGE_UID, UserHandle.getUserId(Process.myUid()));
        data.putExtra(AppInfoBase.ARG_PACKAGE_UID, Process.myUid());
        ActivityController<TestAppLocalePickerActivity> activityController =
                Robolectric.buildActivity(TestAppLocalePickerActivity.class, data);
        Activity activity = activityController.get();
@@ -149,10 +246,75 @@ public class AppLocalePickerActivityTest {
    @Implements(ApplicationPackageManager.class)
    public static class ShadowApplicationPackageManager extends
            org.robolectric.shadows.ShadowApplicationPackageManager {
        private static boolean sNoLaunchEntry = false;

        @Implementation
        protected Object getInstallSourceInfo(String packageName) {
            return new InstallSourceInfo("", null, null, "");
        }

        @Implementation
        protected List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
            if (sNoLaunchEntry) {
                return new ArrayList();
            } else {
                return super.queryIntentActivities(intent, flags);
            }
        }

        private static void setNoLaunchEntry(boolean noLaunchEntry) {
            sNoLaunchEntry = noLaunchEntry;
        }
    }

    @Implements(Resources.class)
    public static class ShadowResources extends
            org.robolectric.shadows.ShadowResources {
        private static boolean sDisAllowPackage = false;

        @Implementation
        public String[] getStringArray(@ArrayRes int id) {
            if (sDisAllowPackage) {
                return new String[]{TEST_PACKAGE_NAME};
            } else {
                return new String[0];
            }
        }

        private static void setDisAllowPackage(boolean disAllowPackage) {
            sDisAllowPackage = disAllowPackage;
        }
    }

    @Implements(UserHandle.class)
    public static class ShadowUserHandle {
        private static int sUserId = 0;
        private static void setUserId(int userId) {
            sUserId = userId;
        }

        @Implementation
        public static int getUserId(int userId) {
            return sUserId;
        }
    }

    @Implements(LocaleConfig.class)
    public static class ShadowLocaleConfig {
        private static int sStatus = 0;

        @Implementation
        public @Nullable LocaleList getSupportedLocales() {
            return LocaleList.forLanguageTags("en-US");
        }

        private static void setStatus(@LocaleConfig.Status int status) {
            sStatus = status;
        }

        @Implementation
        public @LocaleConfig.Status int getStatus() {
            return sStatus;
        }
    }
}