From aa744e8988f0e7b77a71087edd4d2546b58d2f24 Mon Sep 17 00:00:00 2001 From: James Eidson Date: Thu, 14 Aug 2025 19:54:00 +0000 Subject: [PATCH] [nfc] Fix string injection in default payment app selector Backwards compatible port of ag/35084316 Bug: 429417453 Test: Manually by installing settings app Flag: EXEMPT security fix (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6c723a4361950e8e43cc5caf67455bd2f00911d1) Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:b04265c1b84104884654d4957c5fb3a8ac84bc00 Merged-In: I670774a5efa6f543a5e1e06798a5d6ebb1c48c1d Change-Id: I670774a5efa6f543a5e1e06798a5d6ebb1c48c1d --- .../settings/nfc/DefaultPaymentSettings.java | 29 ++++++++++--------- .../android/settings/nfc/PaymentBackend.java | 19 ++++++++++++ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/com/android/settings/nfc/DefaultPaymentSettings.java b/src/com/android/settings/nfc/DefaultPaymentSettings.java index ddac08beb00..440f09e3d9b 100644 --- a/src/com/android/settings/nfc/DefaultPaymentSettings.java +++ b/src/com/android/settings/nfc/DefaultPaymentSettings.java @@ -17,7 +17,6 @@ package com.android.settings.nfc; import android.app.settings.SettingsEnums; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -45,6 +44,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; /** * DefaultPaymentSettings handles the NFC default payment app selection. @@ -53,7 +55,7 @@ public class DefaultPaymentSettings extends DefaultAppPickerFragment { public static final String TAG = "DefaultPaymentSettings"; private PaymentBackend mPaymentBackend; - private List mAppInfos; + private Map mAppInfos; private FooterPreference mFooterPreference; @Override @@ -67,22 +69,19 @@ public class DefaultPaymentSettings extends DefaultAppPickerFragment { } @Override + @SuppressWarnings("NullAway") protected String getDefaultKey() { PaymentAppInfo defaultAppInfo = mPaymentBackend.getDefaultApp(); - if (defaultAppInfo != null) { - return defaultAppInfo.componentName.flattenToString() + " " - + defaultAppInfo.userHandle.getIdentifier(); - } - return null; + if (defaultAppInfo == null) return null; + return defaultAppInfo.getKey(); } @Override protected boolean setDefaultKey(String key) { - String[] keys = key.split(" "); - if (keys.length >= 2) { - mPaymentBackend.setDefaultPaymentApp(ComponentName.unflattenFromString(keys[0]), - Integer.parseInt(keys[1])); - } + PaymentAppInfo appInfo = mAppInfos.get(key); + if (appInfo == null) return true; + mPaymentBackend.setDefaultPaymentApp( + appInfo.componentName, appInfo.userHandle.getIdentifier()); return true; } @@ -90,7 +89,9 @@ public class DefaultPaymentSettings extends DefaultAppPickerFragment { public void onAttach(Context context) { super.onAttach(context); mPaymentBackend = new PaymentBackend(getActivity()); - mAppInfos = mPaymentBackend.getPaymentAppInfos(); + mAppInfos = mPaymentBackend.getPaymentAppInfos() + .stream() + .collect(Collectors.toMap(PaymentAppInfo::getKey, Function.identity())); } @Override @@ -147,7 +148,7 @@ public class DefaultPaymentSettings extends DefaultAppPickerFragment { @Override protected List getCandidates() { final List candidates = new ArrayList<>(); - for (PaymentAppInfo appInfo: mAppInfos) { + for (PaymentAppInfo appInfo: mAppInfos.values()) { UserManager um = getContext().createContextAsUser( appInfo.userHandle, /*flags=*/0).getSystemService(UserManager.class); boolean isManagedProfile = um.isManagedProfile(appInfo.userHandle.getIdentifier()); diff --git a/src/com/android/settings/nfc/PaymentBackend.java b/src/com/android/settings/nfc/PaymentBackend.java index 021d673e152..de733081a1d 100644 --- a/src/com/android/settings/nfc/PaymentBackend.java +++ b/src/com/android/settings/nfc/PaymentBackend.java @@ -36,6 +36,7 @@ import com.android.internal.content.PackageMonitor; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class PaymentBackend { public static final String TAG = "Settings.PaymentBackend"; @@ -52,6 +53,24 @@ public class PaymentBackend { public ComponentName settingsComponent; public UserHandle userHandle; public Drawable icon; + + public String getKey() { + return Integer.toString(hashCode()); + } + + @Override + public int hashCode() { + return Objects.hash(componentName, userHandle); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof PaymentAppInfo)) return false; + PaymentAppInfo appInfo = (PaymentAppInfo) o; + return componentName.equals(appInfo.componentName) + && userHandle.equals(appInfo.userHandle); + } } /**