diff --git a/src/com/android/settings/accounts/AccountTypePreferenceLoader.java b/src/com/android/settings/accounts/AccountTypePreferenceLoader.java index 73583ea8592..7cfeb1cc193 100644 --- a/src/com/android/settings/accounts/AccountTypePreferenceLoader.java +++ b/src/com/android/settings/accounts/AccountTypePreferenceLoader.java @@ -19,6 +19,8 @@ package com.android.settings.accounts; import android.accounts.Account; import android.accounts.AuthenticatorDescription; +import android.content.ClipData; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -177,13 +179,16 @@ public class AccountTypePreferenceLoader { * exploiting the fact that settings has system privileges. */ if (isSafeIntent(pm, prefIntent, acccountType)) { + // Explicitly set an empty ClipData to ensure that we don't offer to + // promote any Uris contained inside for granting purposes + prefIntent.setClipData(ClipData.newPlainText(null, null)); mFragment.getActivity().startActivityAsUser( prefIntent, mUserHandle); } else { Log.e(TAG, - "Refusing to launch authenticator intent because" - + "it exploits Settings permissions: " - + prefIntent); + "Refusing to launch authenticator intent because " + + "it exploits Settings permissions: " + + prefIntent); } return true; } @@ -237,13 +242,19 @@ public class AccountTypePreferenceLoader { } /** - * Determines if the supplied Intent is safe. A safe intent is one that is - * will launch a exported=true activity or owned by the same uid as the + * Determines if the supplied Intent is safe. A safe intent is one that + * will launch an exported=true activity or owned by the same uid as the * authenticator supplying the intent. */ - private boolean isSafeIntent(PackageManager pm, Intent intent, String acccountType) { + @VisibleForTesting + boolean isSafeIntent(PackageManager pm, Intent intent, String accountType) { + if (TextUtils.equals(intent.getScheme(), ContentResolver.SCHEME_CONTENT)) { + Log.e(TAG, "Intent with a content scheme is unsafe."); + return false; + } + AuthenticatorDescription authDesc = - mAuthenticatorHelper.getAccountTypeDescription(acccountType); + mAuthenticatorHelper.getAccountTypeDescription(accountType); ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mUserHandle.getIdentifier()); if (resolveInfo == null) { return false; diff --git a/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java b/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java index 405f6b3dbb8..5e566004a1e 100644 --- a/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java +++ b/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java @@ -16,6 +16,8 @@ package com.android.settings.accounts; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Answers.RETURNS_DEEP_STUBS; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; @@ -26,8 +28,11 @@ import static org.mockito.Mockito.when; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; +import android.content.ClipData; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; +import android.net.Uri; import android.os.UserHandle; import androidx.preference.Preference; @@ -129,4 +134,13 @@ public class AccountTypePreferenceLoaderTest { verify(mPrefLoader).updatePreferenceIntents(prefGroup4, acctType, mAccount); verify(mPrefLoader).updatePreferenceIntents(prefGroup41, acctType, mAccount); } + + @Test + public void isSafeIntent_hasContextScheme_returnFalse() { + Intent intent = new Intent(); + intent.setClipData(ClipData.newRawUri(null, + Uri.parse("content://com.android.settings.files/my_cache/NOTICE.html"))); + + assertThat(mPrefLoader.isSafeIntent(mPackageManager, intent, mAccount.type)).isFalse(); + } }