Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5b23e7cf authored by lpeter's avatar lpeter Committed by Android Build Coastguard Worker
Browse files

Add the protection to avoid data overflow in BinaryXmlSerializer.java

Add an integer overflow check in the writeShort in these two methods:
1.BinaryXmlSerializer#attributeBytesHex
2.BinaryXmlSerializer#attributeBytesBase64

Bug: 307288067
Test: atest BinaryXmlTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2f04963358987679cb4cbab085ec78c1b5e0ed0e)
Merged-In: I81f5ed43342d5b906f36f3733c2115232da90ac1
Change-Id: I81f5ed43342d5b906f36f3733c2115232da90ac1
parent 11a632e1
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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;
+50 −0
Original line number Diff line number Diff line
@@ -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());
        }
    }
}