From c16e6e78c1c8ba40f8c2ff6a4d87afe44590eb7f Mon Sep 17 00:00:00 2001 From: Krishang Garodia Date: Mon, 19 Jun 2023 11:43:45 +0000 Subject: [PATCH] Remove invalid surrogates during bindSelection Test: atest MediaProviderTests Bug: 223793631 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:108f736d0ec6e974c3f947e7e568845b7e039a0a) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a48b01f78f28fc642b144c673bfcd12ae78c5a73) Merged-In: I18b879f1a51394b4739225ec88b862fd6d0d5526 Change-Id: I18b879f1a51394b4739225ec88b862fd6d0d5526 --- .../providers/media/util/DatabaseUtils.java | 36 +++++++++++++++++-- .../media/util/DatabaseUtilsTest.java | 10 ++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/com/android/providers/media/util/DatabaseUtils.java b/src/com/android/providers/media/util/DatabaseUtils.java index 55efafc7f..53ecf964e 100644 --- a/src/com/android/providers/media/util/DatabaseUtils.java +++ b/src/com/android/providers/media/util/DatabaseUtils.java @@ -127,8 +127,9 @@ public class DatabaseUtils { res.append(((Boolean) arg).booleanValue() ? 1 : 0); } else { res.append('\''); - // Escape single quote character while appending the string. - res.append(arg.toString().replace("'", "''")); + // Escape single quote character while appending the string and reject + // invalid unicode. + res.append(escapeSingleQuoteAndRejectInvalidUnicode(arg.toString())); res.append('\''); } break; @@ -142,6 +143,37 @@ public class DatabaseUtils { return res.toString(); } + private static String escapeSingleQuoteAndRejectInvalidUnicode(@NonNull String target) { + final int len = target.length(); + final StringBuilder res = new StringBuilder(len); + boolean lastHigh = false; + + for (int i = 0; i < len; ) { + final char c = target.charAt(i++); + + if (lastHigh != Character.isLowSurrogate(c)) { + Log.e(TAG, "Invalid surrogate in string " + target); + throw new IllegalArgumentException("Invalid surrogate in string " + target); + } + + lastHigh = Character.isHighSurrogate(c); + + // Escape the single quotes by duplicating them + if (c == '\'') { + res.append(c); + } + + res.append(c); + } + + if (lastHigh) { + Log.e(TAG, "Invalid surrogate in string " + target); + throw new IllegalArgumentException("Invalid surrogate in string " + target); + } + + return res.toString(); + } + /** * Returns data type of the given object's value. *

diff --git a/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java b/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java index 685d89704..a90787589 100644 --- a/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java +++ b/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java @@ -39,6 +39,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -126,6 +127,15 @@ public void testBindSelection_singleQuoteCharacter() throws Exception { bindSelection("DATA=?", "Fo''o")); } + @Test + public void testBindSelection_RejectInvalidUnicode() { + assertThrows(IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uD83Do")); + assertThrows(IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uDE00o")); + assertEquals("DATA='Fo\uD83D\uDE00o'", bindSelection("DATA=?", "Fo\uD83D\uDE00o")); + assertThrows( + IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uDE00\uD83Do")); + } + @Test public void testResolveQueryArgs_GroupBy() throws Exception { args.putStringArray(QUERY_ARG_GROUP_COLUMNS, new String[] { "foo", "bar" });