Merge "Mitigate Intent Capturing vulnerability"

This commit is contained in:
Shafik Nassar
2018-12-24 16:13:03 +00:00
committed by Android (Google) Code Review
4 changed files with 125 additions and 22 deletions

View File

@@ -101,6 +101,7 @@ public class ResolverActivity extends Activity {
private AbsListView mAdapterView;
private Button mAlwaysButton;
private Button mOnceButton;
private Button mSettingsButton;
private View mProfileView;
private int mIconDpi;
private int mLastSelected = AbsListView.INVALID_POSITION;
@@ -112,6 +113,7 @@ public class ResolverActivity extends Activity {
private String mReferrerPackage;
private CharSequence mTitle;
private int mDefaultTitleResId;
private boolean mUseLayoutForBrowsables;
// Whether or not this activity supports choosing a default handler for the intent.
private boolean mSupportsAlwaysUseOption;
@@ -192,6 +194,12 @@ public class ResolverActivity extends Activity {
com.android.internal.R.string.whichHomeApplicationNamed,
com.android.internal.R.string.whichHomeApplicationLabel);
// SpR.id.buttonecial titles for BROWSABLE components
public static final int BROWSABLE_TITLE_RES =
com.android.internal.R.string.whichGiveAccessToApplication;
public static final int BROWSABLE_NAMED_TITLE_RES =
com.android.internal.R.string.whichGiveAccessToApplicationNamed;
public final String action;
public final int titleRes;
public final int namedTitleRes;
@@ -283,7 +291,6 @@ public class ResolverActivity extends Activity {
mPackageMonitor.register(this, getMainLooper(), false);
mRegistered = true;
mReferrerPackage = getReferrerPackageName();
mSupportsAlwaysUseOption = supportsAlwaysUseOption;
final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
mIconDpi = am.getLauncherLargeIconDensity();
@@ -293,6 +300,14 @@ public class ResolverActivity extends Activity {
mTitle = title;
mDefaultTitleResId = defaultTitleRes;
mUseLayoutForBrowsables = getTargetIntent() == null
? false
: getTargetIntent().hasCategory(Intent.CATEGORY_BROWSABLE);
// We don't want to support Always Use if browsable layout is being used,
// as to mitigate Intent Capturing vulnerability
mSupportsAlwaysUseOption = supportsAlwaysUseOption && !mUseLayoutForBrowsables;
mIconFactory = IconDrawableFactory.newInstance(this, true);
if (configureContentView(mIntents, initialIntents, rList)) {
return;
@@ -448,13 +463,23 @@ public class ResolverActivity extends Activity {
mSafeForwardingMode = safeForwarding;
}
protected CharSequence getTitleForAction(String action, int defaultTitleRes) {
final ActionTitle title = mResolvingHome ? ActionTitle.HOME : ActionTitle.forAction(action);
protected CharSequence getTitleForAction(Intent intent, int defaultTitleRes) {
final ActionTitle title = mResolvingHome
? ActionTitle.HOME
: ActionTitle.forAction(intent.getAction());
// While there may already be a filtered item, we can only use it in the title if the list
// is already sorted and all information relevant to it is already in the list.
final boolean named = mAdapter.getFilteredPosition() >= 0;
if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
return getString(defaultTitleRes);
} else if (intent.hasCategory(Intent.CATEGORY_BROWSABLE)) {
// If the Intent is BROWSABLE then we need to warn the user that
// they're giving access for the activity to open URLs from this specific host
return named
? getString(ActionTitle.BROWSABLE_NAMED_TITLE_RES, intent.getData().getHost(),
mAdapter.getFilteredItem().getDisplayLabel())
: getString(ActionTitle.BROWSABLE_TITLE_RES, intent.getData().getHost());
} else {
return named
? getString(title.namedTitleRes, mAdapter.getFilteredItem().getDisplayLabel())
@@ -555,7 +580,7 @@ public class ResolverActivity extends Activity {
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
resetAlwaysOrOnceButtonBar();
resetButtonBar();
}
private boolean hasManagedProfile() {
@@ -607,11 +632,23 @@ public class ResolverActivity extends Activity {
public void onButtonClick(View v) {
final int id = v.getId();
startSelected(mAdapter.hasFilteredItem() ?
mAdapter.getFilteredPosition():
mAdapterView.getCheckedItemPosition(),
id == R.id.button_always,
!mAdapter.hasFilteredItem());
int which = mAdapter.hasFilteredItem()
? mAdapter.getFilteredPosition()
: mAdapterView.getCheckedItemPosition();
boolean hasIndexBeenFiltered = !mAdapter.hasFilteredItem();
if (id == R.id.button_app_settings) {
showSettingsForSelected(which, hasIndexBeenFiltered);
} else {
startSelected(which, id == R.id.button_always, hasIndexBeenFiltered);
}
}
private void showSettingsForSelected(int which, boolean hasIndexBeenFiltered) {
ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
Intent in = new Intent().setAction(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS)
.setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
startActivity(in);
}
public void startSelected(int which, boolean always, boolean hasIndexBeenFiltered) {
@@ -995,7 +1032,7 @@ public class ResolverActivity extends Activity {
adapterView.setOnItemClickListener(listener);
adapterView.setOnItemLongClickListener(listener);
if (mSupportsAlwaysUseOption) {
if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) {
listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
}
@@ -1017,7 +1054,7 @@ public class ResolverActivity extends Activity {
CharSequence title = mTitle != null
? mTitle
: getTitleForAction(getTargetIntent().getAction(), mDefaultTitleResId);
: getTitleForAction(getTargetIntent(), mDefaultTitleResId);
if (!TextUtils.isEmpty(title)) {
final TextView titleView = findViewById(R.id.title);
@@ -1051,16 +1088,47 @@ public class ResolverActivity extends Activity {
}
}
public void resetAlwaysOrOnceButtonBar() {
if (mSupportsAlwaysUseOption) {
final ViewGroup buttonLayout = findViewById(R.id.button_bar);
if (buttonLayout != null) {
buttonLayout.setVisibility(View.VISIBLE);
mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
private void resetButtonBar() {
if (!mSupportsAlwaysUseOption && !mUseLayoutForBrowsables) {
return;
}
final ViewGroup buttonLayout = findViewById(R.id.button_bar);
if (buttonLayout != null) {
buttonLayout.setVisibility(View.VISIBLE);
mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
mSettingsButton = (Button) buttonLayout.findViewById(R.id.button_app_settings);
mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
if (mUseLayoutForBrowsables) {
resetSettingsOrOnceButtonBar();
} else {
Log.e(TAG, "Layout unexpectedly does not have a button bar");
resetAlwaysOrOnceButtonBar();
}
} else {
Log.e(TAG, "Layout unexpectedly does not have a button bar");
}
}
private void resetSettingsOrOnceButtonBar() {
//unsetting always button
mAlwaysButton.setVisibility(View.GONE);
// When the items load in, if an item was already selected,
// enable the buttons
if (mAdapterView != null
&& mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
mSettingsButton.setEnabled(true);
mOnceButton.setEnabled(true);
}
}
private void resetAlwaysOrOnceButtonBar() {
// This check needs to be made because layout with default
// doesn't have a settings button
if (mSettingsButton != null) {
//unsetting always button
mSettingsButton.setVisibility(View.GONE);
mSettingsButton = null;
}
if (useLayoutWithDefault()
@@ -1625,7 +1693,7 @@ public class ResolverActivity extends Activity {
@Override
public void run() {
setTitleAndIcon();
resetAlwaysOrOnceButtonBar();
resetButtonBar();
onListRebuilt();
mPostListReadyRunnable = null;
}
@@ -1986,8 +2054,14 @@ public class ResolverActivity extends Activity {
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (!useLayoutWithDefault()
&& (!hasValidSelection || mLastSelected != checkedPos)
&& mAlwaysButton != null) {
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
&& (mAlwaysButton != null || mSettingsButton != null)) {
if (mSettingsButton != null) {
// this implies that the layout for browsables is being used
mSettingsButton.setEnabled(true);
} else {
// this implies that mAlwaysButton != null
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
}
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
mAdapterView.smoothScrollToPosition(checkedPos);

View File

@@ -129,6 +129,18 @@
android:enabled="false"
android:text="@string/activity_resolver_use_always"
android:onClick="onButtonClick" />
<Button
android:id="@+id/button_app_settings"
android:layout_width="wrap_content"
android:layout_gravity="end"
android:maxLines="2"
android:minHeight="@dimen/alert_dialog_button_bar_height"
style="?attr/buttonBarPositiveButtonStyle"
android:layout_height="wrap_content"
android:enabled="false"
android:text="@string/activity_resolver_app_settings"
android:onClick="onButtonClick" />
</LinearLayout>
</com.android.internal.widget.ResolverDrawerLayout>

View File

@@ -3066,6 +3066,14 @@
<string name="whichViewApplicationNamed">Open with %1$s</string>
<!-- Label for a link to a intent resolver dialog to view something -->
<string name="whichViewApplicationLabel">Open</string>
<!-- Title of intent resolver dialog when selecting a viewer application that opens URI
[CHAR LIMIT=128]. -->
<string name="whichGiveAccessToApplication">Give access to open <xliff:g id="host" example="mail.google.com">%1$s</xliff:g> links with</string>
<!-- Title of intent resolver dialog when selecting a viewer application that opens URI
and a previously used application is known [CHAR LIMIT=128]. -->
<string name="whichGiveAccessToApplicationNamed">Give access to open <xliff:g id="host" example="mail.google.com">%1$s</xliff:g> links with <xliff:g id="application" example="Gmail">%2$s</xliff:g></string>
<!-- Label for a link to an intent resolver dialog to open URI [CHAR LIMIT=16] -->
<string name="whichGiveAccessToApplicationLabel">Give access</string>
<!-- Title of intent resolver dialog when selecting an editor application to run. -->
<string name="whichEditApplication">Edit with</string>
<!-- Title of intent resolver dialog when selecting an editor application to run
@@ -4156,6 +4164,10 @@
from the activity resolver to use just this once. [CHAR LIMIT=25] -->
<string name="activity_resolver_use_once">Just once</string>
<!-- Title for a button to choose to go to
'Open by Default' app settings. [CHAR LIMIT=25] -->
<string name="activity_resolver_app_settings">Settings</string>
<!-- Text for the toast that is shown when the user clicks on a launcher that
doesn't support the work profile. [CHAR LIMIT=100] -->
<string name="activity_resolver_work_profiles_support">%1$s doesn\'t support work profile</string>

View File

@@ -2144,6 +2144,7 @@
<java-symbol type="id" name="resolver_list" />
<java-symbol type="id" name="button_once" />
<java-symbol type="id" name="button_always" />
<java-symbol type="id" name="button_app_settings" />
<java-symbol type="integer" name="config_globalActionsKeyTimeout" />
<java-symbol type="integer" name="config_maxResolverActivityColumns" />
<java-symbol type="array" name="config_notificationSignalExtractors" />
@@ -2499,11 +2500,15 @@
<java-symbol type="bool" name="config_use_voip_mode_for_ims" />
<java-symbol type="attr" name="touchscreenBlocksFocus" />
<java-symbol type="layout" name="resolver_list_with_default" />
<java-symbol type="string" name="activity_resolver_app_settings" />
<java-symbol type="string" name="whichApplicationNamed" />
<java-symbol type="string" name="whichApplicationLabel" />
<java-symbol type="string" name="whichViewApplication" />
<java-symbol type="string" name="whichViewApplicationNamed" />
<java-symbol type="string" name="whichViewApplicationLabel" />
<java-symbol type="string" name="whichGiveAccessToApplication" />
<java-symbol type="string" name="whichGiveAccessToApplicationNamed" />
<java-symbol type="string" name="whichGiveAccessToApplicationLabel" />
<java-symbol type="string" name="whichEditApplication" />
<java-symbol type="string" name="whichEditApplicationNamed" />
<java-symbol type="string" name="whichEditApplicationLabel" />