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

Commit a3893027 authored by Pawan Wagh's avatar Pawan Wagh
Browse files

Adding allocation size check when creating arrays in java parcel

Unchecked allocations were causing OOM issues in services. Adding
a check while allocating array.

Bug: 205282403
Test: m && acloud delete --all && acloud create --local-image --local-instance
&& atest -c android.os.cts.ParcelTest

Merged-In: I8c728166540f22ebaded5025f7b3190568da5a6b
Change-Id: I8c728166540f22ebaded5025f7b3190568da5a6b
parent c2fa03fc
Loading
Loading
Loading
Loading
+107 −0
Original line number Original line Diff line number Diff line
@@ -363,6 +363,22 @@ public final class Parcel {
    // see libbinder's binder/Status.h
    // see libbinder's binder/Status.h
    private static final int EX_TRANSACTION_FAILED = -129;
    private static final int EX_TRANSACTION_FAILED = -129;


    // Allow limit of 1 MB for allocating arrays
    private static final int ARRAY_ALLOCATION_LIMIT = 1000000;

    // Following type size are used to determine allocation size while creating arrays
    private static final int SIZE_BYTE = 1;
    private static final int SIZE_CHAR = 2;
    private static final int SIZE_SHORT = 2;
    private static final int SIZE_BOOLEAN = 4;
    private static final int SIZE_INT = 4;
    private static final int SIZE_FLOAT = 4;
    private static final int SIZE_DOUBLE = 8;
    private static final int SIZE_LONG = 8;

    // Assume the least possible size for complex objects
    private static final int SIZE_COMPLEX_TYPE = 1;

    @CriticalNative
    @CriticalNative
    private static native void nativeMarkSensitive(long nativePtr);
    private static native void nativeMarkSensitive(long nativePtr);
    @FastNative
    @FastNative
@@ -1503,9 +1519,63 @@ public final class Parcel {
        }
        }
    }
    }


    private static <T> int getItemTypeSize(@NonNull Class<T> arrayClass) {
        final Class<?> componentType = arrayClass.getComponentType();
        // typeSize has been referred from respective create*Array functions
        if (componentType == boolean.class) {
            return SIZE_BOOLEAN;
        } else if (componentType == byte.class) {
            return SIZE_BYTE;
        } else if (componentType == char.class) {
            return SIZE_CHAR;
        } else if (componentType == int.class) {
            return SIZE_INT;
        } else if (componentType == long.class) {
            return SIZE_LONG;
        } else if (componentType == float.class) {
            return SIZE_FLOAT;
        } else if (componentType == double.class) {
            return SIZE_DOUBLE;
        }

        return SIZE_COMPLEX_TYPE;
    }

    private void ensureWithinMemoryLimit(int typeSize, @NonNull int... dimensions) {
        // For Multidimensional arrays, Calculate total object
        // which will be allocated.
        int totalObjects = 1;
        try {
            for (int dimension : dimensions) {
                totalObjects = Math.multiplyExact(totalObjects, dimension);
            }
        } catch (ArithmeticException e) {
            Log.e(TAG, "ArithmeticException occurred while multiplying dimensions " + e);
        }
        ensureWithinMemoryLimit(typeSize, totalObjects);
    }

    private void ensureWithinMemoryLimit(int typeSize, @NonNull int length) {
        int estimatedAllocationSize = 0;
        try {
            estimatedAllocationSize = Math.multiplyExact(typeSize, length);
        } catch (ArithmeticException e) {
            Log.e(TAG, "ArithmeticException occurred while multiplying values " + typeSize
                    + " and "  + length + " Exception: " + e);
        }

        boolean isInBinderTransaction = Binder.isDirectlyHandlingTransaction();
        if (isInBinderTransaction && (estimatedAllocationSize > ARRAY_ALLOCATION_LIMIT)) {
            Log.e(TAG, "Trying to Allocate " + estimatedAllocationSize
                    + " memory, In Binder Transaction : " + isInBinderTransaction);
        }
    }

    @Nullable
    @Nullable
    public final boolean[] createBooleanArray() {
    public final boolean[] createBooleanArray() {
        int N = readInt();
        int N = readInt();
        // Assuming size of 4 byte for boolean.
        ensureWithinMemoryLimit(SIZE_BOOLEAN, N);
        // >>2 as a fast divide-by-4 works in the create*Array() functions
        // >>2 as a fast divide-by-4 works in the create*Array() functions
        // because dataAvail() will never return a negative number.  4 is
        // because dataAvail() will never return a negative number.  4 is
        // the size of a stored boolean in the stream.
        // the size of a stored boolean in the stream.
@@ -1548,6 +1618,8 @@ public final class Parcel {
    @Nullable
    @Nullable
    public short[] createShortArray() {
    public short[] createShortArray() {
        int n = readInt();
        int n = readInt();
        // Assuming size of 2 byte for short.
        ensureWithinMemoryLimit(SIZE_SHORT, n);
        if (n >= 0 && n <= (dataAvail() >> 2)) {
        if (n >= 0 && n <= (dataAvail() >> 2)) {
            short[] val = new short[n];
            short[] val = new short[n];
            for (int i = 0; i < n; i++) {
            for (int i = 0; i < n; i++) {
@@ -1586,6 +1658,8 @@ public final class Parcel {
    @Nullable
    @Nullable
    public final char[] createCharArray() {
    public final char[] createCharArray() {
        int N = readInt();
        int N = readInt();
        // Assuming size of 2 byte for char.
        ensureWithinMemoryLimit(SIZE_CHAR, N);
        if (N >= 0 && N <= (dataAvail() >> 2)) {
        if (N >= 0 && N <= (dataAvail() >> 2)) {
            char[] val = new char[N];
            char[] val = new char[N];
            for (int i=0; i<N; i++) {
            for (int i=0; i<N; i++) {
@@ -1623,6 +1697,8 @@ public final class Parcel {
    @Nullable
    @Nullable
    public final int[] createIntArray() {
    public final int[] createIntArray() {
        int N = readInt();
        int N = readInt();
        // Assuming size of 4 byte for int.
        ensureWithinMemoryLimit(SIZE_INT, N);
        if (N >= 0 && N <= (dataAvail() >> 2)) {
        if (N >= 0 && N <= (dataAvail() >> 2)) {
            int[] val = new int[N];
            int[] val = new int[N];
            for (int i=0; i<N; i++) {
            for (int i=0; i<N; i++) {
@@ -1660,6 +1736,8 @@ public final class Parcel {
    @Nullable
    @Nullable
    public final long[] createLongArray() {
    public final long[] createLongArray() {
        int N = readInt();
        int N = readInt();
        // Assuming size of 8 byte for long.
        ensureWithinMemoryLimit(SIZE_LONG, N);
        // >>3 because stored longs are 64 bits
        // >>3 because stored longs are 64 bits
        if (N >= 0 && N <= (dataAvail() >> 3)) {
        if (N >= 0 && N <= (dataAvail() >> 3)) {
            long[] val = new long[N];
            long[] val = new long[N];
@@ -1698,6 +1776,8 @@ public final class Parcel {
    @Nullable
    @Nullable
    public final float[] createFloatArray() {
    public final float[] createFloatArray() {
        int N = readInt();
        int N = readInt();
        // Assuming size of 4 byte for float.
        ensureWithinMemoryLimit(SIZE_FLOAT, N);
        // >>2 because stored floats are 4 bytes
        // >>2 because stored floats are 4 bytes
        if (N >= 0 && N <= (dataAvail() >> 2)) {
        if (N >= 0 && N <= (dataAvail() >> 2)) {
            float[] val = new float[N];
            float[] val = new float[N];
@@ -1736,6 +1816,8 @@ public final class Parcel {
    @Nullable
    @Nullable
    public final double[] createDoubleArray() {
    public final double[] createDoubleArray() {
        int N = readInt();
        int N = readInt();
        // Assuming size of 8 byte for double.
        ensureWithinMemoryLimit(SIZE_DOUBLE, N);
        // >>3 because stored doubles are 8 bytes
        // >>3 because stored doubles are 8 bytes
        if (N >= 0 && N <= (dataAvail() >> 3)) {
        if (N >= 0 && N <= (dataAvail() >> 3)) {
            double[] val = new double[N];
            double[] val = new double[N];
@@ -1789,6 +1871,7 @@ public final class Parcel {
    @Nullable
    @Nullable
    public final String[] createString8Array() {
    public final String[] createString8Array() {
        int N = readInt();
        int N = readInt();
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        if (N >= 0) {
        if (N >= 0) {
            String[] val = new String[N];
            String[] val = new String[N];
            for (int i=0; i<N; i++) {
            for (int i=0; i<N; i++) {
@@ -1829,6 +1912,7 @@ public final class Parcel {
    @Nullable
    @Nullable
    public final String[] createString16Array() {
    public final String[] createString16Array() {
        int N = readInt();
        int N = readInt();
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        if (N >= 0) {
        if (N >= 0) {
            String[] val = new String[N];
            String[] val = new String[N];
            for (int i=0; i<N; i++) {
            for (int i=0; i<N; i++) {
@@ -1921,6 +2005,7 @@ public final class Parcel {
    @Nullable
    @Nullable
    public final IBinder[] createBinderArray() {
    public final IBinder[] createBinderArray() {
        int N = readInt();
        int N = readInt();
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        if (N >= 0) {
        if (N >= 0) {
            IBinder[] val = new IBinder[N];
            IBinder[] val = new IBinder[N];
            for (int i=0; i<N; i++) {
            for (int i=0; i<N; i++) {
@@ -1955,6 +2040,7 @@ public final class Parcel {
    public final <T extends IInterface> T[] createInterfaceArray(
    public final <T extends IInterface> T[] createInterfaceArray(
            @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
            @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
        int N = readInt();
        int N = readInt();
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        if (N >= 0) {
        if (N >= 0) {
            T[] val = newArray.apply(N);
            T[] val = newArray.apply(N);
            for (int i=0; i<N; i++) {
            for (int i=0; i<N; i++) {
@@ -3201,6 +3287,7 @@ public final class Parcel {
        if (N < 0) {
        if (N < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        FileDescriptor[] f = new FileDescriptor[N];
        FileDescriptor[] f = new FileDescriptor[N];
        for (int i = 0; i < N; i++) {
        for (int i = 0; i < N; i++) {
            f[i] = readRawFileDescriptor();
            f[i] = readRawFileDescriptor();
@@ -3667,6 +3754,7 @@ public final class Parcel {
        if (N < 0) {
        if (N < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        ArrayList<T> l = new ArrayList<T>(N);
        ArrayList<T> l = new ArrayList<T>(N);
        while (N > 0) {
        while (N > 0) {
            l.add(readTypedObject(c));
            l.add(readTypedObject(c));
@@ -3721,6 +3809,7 @@ public final class Parcel {
        if (count < 0) {
        if (count < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, count);
        final SparseArray<T> array = new SparseArray<>(count);
        final SparseArray<T> array = new SparseArray<>(count);
        for (int i = 0; i < count; i++) {
        for (int i = 0; i < count; i++) {
            final int index = readInt();
            final int index = readInt();
@@ -3749,6 +3838,7 @@ public final class Parcel {
        if (count < 0) {
        if (count < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, count);
        final ArrayMap<String, T> map = new ArrayMap<>(count);
        final ArrayMap<String, T> map = new ArrayMap<>(count);
        for (int i = 0; i < count; i++) {
        for (int i = 0; i < count; i++) {
            final String key = readString();
            final String key = readString();
@@ -3775,6 +3865,7 @@ public final class Parcel {
        if (N < 0) {
        if (N < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        ArrayList<String> l = new ArrayList<String>(N);
        ArrayList<String> l = new ArrayList<String>(N);
        while (N > 0) {
        while (N > 0) {
            l.add(readString());
            l.add(readString());
@@ -3800,6 +3891,7 @@ public final class Parcel {
        if (N < 0) {
        if (N < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        ArrayList<IBinder> l = new ArrayList<IBinder>(N);
        ArrayList<IBinder> l = new ArrayList<IBinder>(N);
        while (N > 0) {
        while (N > 0) {
            l.add(readStrongBinder());
            l.add(readStrongBinder());
@@ -3826,6 +3918,7 @@ public final class Parcel {
        if (N < 0) {
        if (N < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        ArrayList<T> l = new ArrayList<T>(N);
        ArrayList<T> l = new ArrayList<T>(N);
        while (N > 0) {
        while (N > 0) {
            l.add(asInterface.apply(readStrongBinder()));
            l.add(asInterface.apply(readStrongBinder()));
@@ -3985,6 +4078,7 @@ public final class Parcel {
        if (N < 0) {
        if (N < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
        T[] l = c.newArray(N);
        T[] l = c.newArray(N);
        for (int i=0; i<N; i++) {
        for (int i=0; i<N; i++) {
            l[i] = readTypedObject(c);
            l[i] = readTypedObject(c);
@@ -4213,6 +4307,10 @@ public final class Parcel {
            while (innermost.isArray()) {
            while (innermost.isArray()) {
                innermost = innermost.getComponentType();
                innermost = innermost.getComponentType();
            }
            }

            int typeSize = getItemTypeSize(innermost);
            ensureWithinMemoryLimit(typeSize, dimensions);

            val = (T) Array.newInstance(innermost, dimensions);
            val = (T) Array.newInstance(innermost, dimensions);
            for (int i = 0; i < length; i++) {
            for (int i = 0; i < length; i++) {
                readFixedArray(Array.get(val, i));
                readFixedArray(Array.get(val, i));
@@ -4269,6 +4367,10 @@ public final class Parcel {
            while (innermost.isArray()) {
            while (innermost.isArray()) {
                innermost = innermost.getComponentType();
                innermost = innermost.getComponentType();
            }
            }

            int typeSize = getItemTypeSize(innermost);
            ensureWithinMemoryLimit(typeSize, dimensions);

            val = (T) Array.newInstance(innermost, dimensions);
            val = (T) Array.newInstance(innermost, dimensions);
            for (int i = 0; i < length; i++) {
            for (int i = 0; i < length; i++) {
                readFixedArray(Array.get(val, i), asInterface);
                readFixedArray(Array.get(val, i), asInterface);
@@ -4324,6 +4426,10 @@ public final class Parcel {
            while (innermost.isArray()) {
            while (innermost.isArray()) {
                innermost = innermost.getComponentType();
                innermost = innermost.getComponentType();
            }
            }

            int typeSize = getItemTypeSize(innermost);
            ensureWithinMemoryLimit(typeSize, dimensions);

            val = (T) Array.newInstance(innermost, dimensions);
            val = (T) Array.newInstance(innermost, dimensions);
            for (int i = 0; i < length; i++) {
            for (int i = 0; i < length; i++) {
                readFixedArray(Array.get(val, i), c);
                readFixedArray(Array.get(val, i), c);
@@ -5069,6 +5175,7 @@ public final class Parcel {
        if (n < 0) {
        if (n < 0) {
            return null;
            return null;
        }
        }
        ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, n);
        T[] p = (T[]) ((clazz == null) ? new Parcelable[n] : Array.newInstance(clazz, n));
        T[] p = (T[]) ((clazz == null) ? new Parcelable[n] : Array.newInstance(clazz, n));
        for (int i = 0; i < n; i++) {
        for (int i = 0; i < n; i++) {
            p[i] = readParcelableInternal(loader, clazz);
            p[i] = readParcelableInternal(loader, clazz);