Resolve StatusHints image exploit across user.
Because of the INTERACT_ACROSS_USERS permission, an app that implements a ConnectionService can upload an image icon belonging to another user by setting it in the StatusHints. Validating the construction of the StatusHints on the calling user would prevent a malicious app from registering a connection service with the embedded image icon from a different user. From additional feedback, this CL also addresses potential vulnerabilities in an app being able to directly invoke the binder for a means to manipulate the contents of the bundle that are passed with it. The targeted points of entry are in ConnectionServiceWrapper for the following APIs: handleCreateConnectionComplete, setStatusHints, addConferenceCall, and addExistingConnection. Fixes: 280797684 Test: Manual (verified that original exploit is no longer an issue). Test: Unit test for validating image in StatusHints constructor. Test: Unit tests to address vulnerabilities via the binder. Change-Id: I6e70e238b3a5ace1cab41ec5796a6bb4d79769f2 Merged-In: I6e70e238b3a5ace1cab41ec5796a6bb4d79769f2
This commit is contained in:
@@ -21,12 +21,12 @@ import android.os.Bundle;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.android.internal.telecom.IVideoProvider;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.android.internal.telecom.IVideoProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A parcelable representation of a conference connection.
|
* A parcelable representation of a conference connection.
|
||||||
* @hide
|
* @hide
|
||||||
@@ -287,6 +287,14 @@ public final class ParcelableConference implements Parcelable {
|
|||||||
return mCallDirection;
|
return mCallDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCallerDisplayName() {
|
||||||
|
return mCallerDisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCallerDisplayNamePresentation() {
|
||||||
|
return mCallerDisplayNamePresentation;
|
||||||
|
}
|
||||||
|
|
||||||
public static final @android.annotation.NonNull Parcelable.Creator<ParcelableConference> CREATOR =
|
public static final @android.annotation.NonNull Parcelable.Creator<ParcelableConference> CREATOR =
|
||||||
new Parcelable.Creator<ParcelableConference> () {
|
new Parcelable.Creator<ParcelableConference> () {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,14 +16,19 @@
|
|||||||
|
|
||||||
package android.telecom;
|
package android.telecom;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -33,7 +38,7 @@ import java.util.Objects;
|
|||||||
public final class StatusHints implements Parcelable {
|
public final class StatusHints implements Parcelable {
|
||||||
|
|
||||||
private final CharSequence mLabel;
|
private final CharSequence mLabel;
|
||||||
private final Icon mIcon;
|
private Icon mIcon;
|
||||||
private final Bundle mExtras;
|
private final Bundle mExtras;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,10 +53,30 @@ public final class StatusHints implements Parcelable {
|
|||||||
|
|
||||||
public StatusHints(CharSequence label, Icon icon, Bundle extras) {
|
public StatusHints(CharSequence label, Icon icon, Bundle extras) {
|
||||||
mLabel = label;
|
mLabel = label;
|
||||||
mIcon = icon;
|
mIcon = validateAccountIconUserBoundary(icon, Binder.getCallingUserHandle());
|
||||||
mExtras = extras;
|
mExtras = extras;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param icon
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public StatusHints(@Nullable Icon icon) {
|
||||||
|
mLabel = null;
|
||||||
|
mExtras = null;
|
||||||
|
mIcon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param icon
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void setIcon(@Nullable Icon icon) {
|
||||||
|
mIcon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A package used to load the icon.
|
* @return A package used to load the icon.
|
||||||
*
|
*
|
||||||
@@ -112,6 +137,30 @@ public final class StatusHints implements Parcelable {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the StatusHints image icon to see if it's not in the calling user space.
|
||||||
|
* Invalidates the icon if so, otherwise returns back the original icon.
|
||||||
|
*
|
||||||
|
* @param icon
|
||||||
|
* @return icon (validated)
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static Icon validateAccountIconUserBoundary(Icon icon, UserHandle callingUserHandle) {
|
||||||
|
// Refer to Icon#getUriString for context. The URI string is invalid for icons of
|
||||||
|
// incompatible types.
|
||||||
|
if (icon != null && (icon.getType() == Icon.TYPE_URI
|
||||||
|
|| icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
|
||||||
|
String encodedUser = icon.getUri().getEncodedUserInfo();
|
||||||
|
// If there is no encoded user, the URI is calling into the calling user space
|
||||||
|
if (encodedUser != null) {
|
||||||
|
int userId = Integer.parseInt(encodedUser);
|
||||||
|
// Do not try to save the icon if the user id isn't in the calling user space.
|
||||||
|
if (userId != callingUserHandle.getIdentifier()) return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel out, int flags) {
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
out.writeCharSequence(mLabel);
|
out.writeCharSequence(mLabel);
|
||||||
|
|||||||
Reference in New Issue
Block a user