InputMethodSubtypeArray: prevent negative count injection Fixes an issue where negative counts could be injected via the Parcel constructor. The writeToParcel method in that case would write data that a subsequent read would not consume. Fixes: 277916797 Fixes: 354682735 Test: atest InputMethodSubtypeArrayTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:23933354757ddd81202fed5b3b9fe7402c6c1164) Merged-In: I7e881d82415051179c59bf5df97f8ba0a41e693e Change-Id: I7e881d82415051179c59bf5df97f8ba0a41e693e
diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java index 50e95c8..ee36dc7 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java +++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
@@ -17,6 +17,7 @@ package android.view.inputmethod; import android.compat.annotation.UnsupportedAppUsage; +import android.os.BadParcelableException; import android.os.Parcel; import android.util.Slog; @@ -69,6 +70,9 @@ */ public InputMethodSubtypeArray(final Parcel source) { mCount = source.readInt(); + if (mCount < 0) { + throw new BadParcelableException("mCount must be non-negative."); + } if (mCount > 0) { mDecompressedSize = source.readInt(); mCompressedData = source.createByteArray();
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java index e2fb46a..5af8558 100644 --- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java +++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
@@ -16,9 +16,14 @@ package android.view.inputmethod; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.junit.Assert.assertEquals; +import android.os.BadParcelableException; import android.os.Parcel; +import android.platform.test.annotations.Presubmit; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; import androidx.test.filters.SmallTest; @@ -31,6 +36,7 @@ @SmallTest @RunWith(AndroidJUnit4.class) +@Presubmit public class InputMethodSubtypeArrayTest { @Test @@ -59,6 +65,36 @@ assertEquals(clonedArray.get(2), clonedClonedArray.get(2)); } + @Test + public void testNegativeCount() throws Exception { + InputMethodSubtypeArray negativeCountArray; + try { + // Construct a InputMethodSubtypeArray with: mCount = -1 + Parcel p = Parcel.obtain(); + p.writeInt(-1); + p.setDataPosition(0); + negativeCountArray = new InputMethodSubtypeArray(p); + } catch (BadParcelableException e) { + // Expected with fix: Prevent negative mCount + assertThat(e).hasMessageThat().contains("mCount"); + return; + } + assertWithMessage("Test set-up failed") + .that(negativeCountArray.getCount()).isEqualTo(-1); + + Parcel p = Parcel.obtain(); + // Writes: int (mCount), int (mDecompressedSize), byte[] (mCompressedData) + negativeCountArray.writeToParcel(p); + p.setDataPosition(0); + // Reads: int (mCount) + // Leaves: int (mDecompressedSize), byte[] (mCompressedData) + new InputMethodSubtypeArray(p); + + assertWithMessage("Didn't read all data that was previously written") + .that(p.dataPosition()) + .isEqualTo(p.dataSize()); + } + InputMethodSubtypeArray cloneViaParcel(final InputMethodSubtypeArray original) { Parcel parcel = null; try {