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

Commit 58e4b73d authored by Arc Wang's avatar Arc Wang Committed by Android Build Coastguard Worker
Browse files

Settings 2-pane deep link vulnerabilities

Settings app must not start an deep link Activity if
1. The deep link Activity is not exported.
or
2. Calling package does not have the permission to
   start the deep link Activity.

Bug: 250589026
Test: make RunSettingsRoboTests ROBOTEST_FILTER=SettingsHomepageActivityTest
Change-Id: I9a3bddfa5d9d1d2e924dd6f3e5e07dca6c11664f
Merged-In: I9a3bddfa5d9d1d2e924dd6f3e5e07dca6c11664f
(cherry picked from commit 434c8934)
Merged-In: I9a3bddfa5d9d1d2e924dd6f3e5e07dca6c11664f
parent 68441c0c
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -43,6 +45,7 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toolbar;

import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
@@ -65,6 +68,7 @@ import com.android.settings.core.CategoryMixin;
import com.android.settings.core.FeatureFlags;
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.PasswordUtils;
import com.android.settingslib.Utils;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;

@@ -431,6 +435,32 @@ public class SettingsHomepageActivity extends FragmentActivity implements
            finish();
            return;
        }

        if (!TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()),
                getPackageName())) {
            ActivityInfo targetActivityInfo = null;
            try {
                targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName,
                        /* flags= */ 0);
            } catch (PackageManager.NameNotFoundException e) {
                Log.e(TAG, "Failed to get target ActivityInfo: " + e);
                finish();
                return;
            }

            if (!targetActivityInfo.exported) {
                Log.e(TAG, "Must not launch an unexported Actvity for deep link");
                finish();
                return;
            }

            if (!isCallingAppPermitted(targetActivityInfo.permission)) {
                Log.e(TAG, "Calling app must have the permission of deep link Activity");
                finish();
                return;
            }
        }

        targetIntent.setComponent(targetComponentName);

        // To prevent launchDeepLinkIntentToRight again for configuration change.
@@ -472,6 +502,12 @@ public class SettingsHomepageActivity extends FragmentActivity implements
        }
    }

    @VisibleForTesting
    boolean isCallingAppPermitted(String permission) {
        return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted(
                this, getActivityToken(), permission);
    }

    private String getHighlightMenuKey() {
        final Intent intent = getIntent();
        if (intent != null && TextUtils.equals(intent.getAction(),
+35 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE

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

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -37,9 +39,11 @@ import androidx.fragment.app.Fragment;
import com.android.settings.R;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest;
import com.android.settings.testutils.shadow.ShadowPasswordUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,6 +70,11 @@ public class SettingsHomepageActivityTest {
        MockitoAnnotations.initMocks(this);
    }

    @After
    public void tearDown() {
        ShadowPasswordUtils.reset();
    }

    @Test
    public void launch_shouldHaveAnimationForIaFragment() {
        final SettingsHomepageActivity activity = Robolectric.buildActivity(
@@ -195,6 +204,32 @@ public class SettingsHomepageActivityTest {
                & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0);
    }

    @Test
    @Config(shadows = {ShadowPasswordUtils.class})
    public void isCallingAppPermitted_emptyPermission_returnTrue() {
        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());

        assertTrue(homepageActivity.isCallingAppPermitted(""));
    }

    @Test
    @Config(shadows = {ShadowPasswordUtils.class})
    public void isCallingAppPermitted_noGrantedPermission_returnFalse() {
        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());

        assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST"));
    }

    @Test
    @Config(shadows = {ShadowPasswordUtils.class})
    public void isCallingAppPermitted_grantedPermission_returnTrue() {
        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
        String permission = "android.permission.TEST";
        ShadowPasswordUtils.addGrantedPermission(permission);

        assertTrue(homepageActivity.isCallingAppPermitted(permission));
    }

    @Implements(SuggestionFeatureProviderImpl.class)
    public static class ShadowSuggestionFeatureProviderImpl {