From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Pranav Madapurmath Date: Thu, 25 May 2023 21:58:19 +0000 Subject: [PATCH] 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. (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:48223d6034907349c6a3fab3018c1b37d86367af) Merged-In: I6e70e238b3a5ace1cab41ec5796a6bb4d79769f2 Change-Id: I6e70e238b3a5ace1cab41ec5796a6bb4d79769f2 --- .../android/telecom/ParcelableConference.java | 8 +++ .../java/android/telecom/StatusHints.java | 53 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java index ede05943772e..b2f8ac8cb0ec 100644 --- a/telecomm/java/android/telecom/ParcelableConference.java +++ b/telecomm/java/android/telecom/ParcelableConference.java @@ -155,6 +155,14 @@ public final class ParcelableConference implements Parcelable { return mAddressPresentation; } + public String getCallerDisplayName() { + return mCallerDisplayName; + } + + public int getCallerDisplayNamePresentation() { + return mCallerDisplayNamePresentation; + } + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator () { @Override diff --git a/telecomm/java/android/telecom/StatusHints.java b/telecomm/java/android/telecom/StatusHints.java index 762c93a49022..761eab81eb62 100644 --- a/telecomm/java/android/telecom/StatusHints.java +++ b/telecomm/java/android/telecom/StatusHints.java @@ -16,14 +16,19 @@ package android.telecom; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.ComponentName; import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.os.Binder; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.UserHandle; + +import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; @@ -33,7 +38,7 @@ import java.util.Objects; public final class StatusHints implements Parcelable { private final CharSequence mLabel; - private final Icon mIcon; + private Icon mIcon; private final Bundle mExtras; /** @@ -48,10 +53,30 @@ public final class StatusHints implements Parcelable { public StatusHints(CharSequence label, Icon icon, Bundle extras) { mLabel = label; - mIcon = icon; + mIcon = validateAccountIconUserBoundary(icon, Binder.getCallingUserHandle()); 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. * @@ -112,6 +137,30 @@ public final class StatusHints implements Parcelable { 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 public void writeToParcel(Parcel out, int flags) { out.writeCharSequence(mLabel);