diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java index 9df4bdb157c84b81f354316032844330037c3b06..6e33dada95895f52bee38cfc7cdaef558dee7e42 100644 --- a/core/java/com/android/internal/util/BinaryXmlSerializer.java +++ b/core/java/com/android/internal/util/BinaryXmlSerializer.java @@ -97,6 +97,8 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer { */ private static final int BUFFER_SIZE = 32_768; + private static final int MAX_UNSIGNED_SHORT = 65_535; + private FastDataOutput mOut; /** @@ -221,6 +223,10 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer { if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); mOut.writeByte(ATTRIBUTE | TYPE_BYTES_HEX); mOut.writeInternedUTF(name); + if (value.length > MAX_UNSIGNED_SHORT) { + throw new IOException("attributeBytesHex: input size (" + value.length + + ") exceeds maximum allowed size (" + MAX_UNSIGNED_SHORT + ")"); + } mOut.writeShort(value.length); mOut.write(value); return this; @@ -232,6 +238,10 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer { if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); mOut.writeByte(ATTRIBUTE | TYPE_BYTES_BASE64); mOut.writeInternedUTF(name); + if (value.length > MAX_UNSIGNED_SHORT) { + throw new IOException("attributeBytesBase64: input size (" + value.length + + ") exceeds maximum allowed size (" + MAX_UNSIGNED_SHORT + ")"); + } mOut.writeShort(value.length); mOut.write(value); return this; diff --git a/core/tests/coretests/src/android/util/BinaryXmlTest.java b/core/tests/coretests/src/android/util/BinaryXmlTest.java index fd625dce02540cb00a32539d4a42119a0a098184..b369868c0d9aec1a42e22b99415b966b1899137c 100644 --- a/core/tests/coretests/src/android/util/BinaryXmlTest.java +++ b/core/tests/coretests/src/android/util/BinaryXmlTest.java @@ -24,6 +24,8 @@ import static android.util.XmlTest.doVerifyRead; import static android.util.XmlTest.doVerifyWrite; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.os.PersistableBundle; @@ -38,12 +40,15 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; @RunWith(AndroidJUnit4.class) public class BinaryXmlTest { + private static final int MAX_UNSIGNED_SHORT = 65_535; + /** * Verify that we can write and read large numbers of interned * {@link String} values. @@ -167,4 +172,49 @@ public class BinaryXmlTest { } } } + + @Test + public void testAttributeBytes_BinaryDataOverflow() throws Exception { + final TypedXmlSerializer out = Xml.newBinarySerializer(); + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + out.setOutput(os, StandardCharsets.UTF_8.name()); + + final byte[] testBytes = new byte[MAX_UNSIGNED_SHORT + 1]; + assertThrows(IOException.class, + () -> out.attributeBytesHex(/* namespace */ null, /* name */ "attributeBytesHex", + testBytes)); + + assertThrows(IOException.class, + () -> out.attributeBytesBase64(/* namespace */ null, /* name */ + "attributeBytesBase64", testBytes)); + } + + @Test + public void testAttributeBytesHex_MaximumBinaryData() throws Exception { + final TypedXmlSerializer out = Xml.newBinarySerializer(); + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + out.setOutput(os, StandardCharsets.UTF_8.name()); + + final byte[] testBytes = new byte[MAX_UNSIGNED_SHORT]; + try { + out.attributeBytesHex(/* namespace */ null, /* name */ "attributeBytesHex", testBytes); + } catch (Exception e) { + fail("testAttributeBytesHex fails with exception: " + e.toString()); + } + } + + @Test + public void testAttributeBytesBase64_MaximumBinaryData() throws Exception { + final TypedXmlSerializer out = Xml.newBinarySerializer(); + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + out.setOutput(os, StandardCharsets.UTF_8.name()); + + final byte[] testBytes = new byte[MAX_UNSIGNED_SHORT]; + try { + out.attributeBytesBase64(/* namespace */ null, /* name */ "attributeBytesBase64", + testBytes); + } catch (Exception e) { + fail("testAttributeBytesBase64 fails with exception: " + e.toString()); + } + } }