From b701fb182bdb32dbafc72406cc27480e12925d71 Mon Sep 17 00:00:00 2001 From: Santhosh Behara Date: Fri, 15 Sep 2017 05:28:04 -0700 Subject: [PATCH] mm-video-v4l2: venc: Avoid buffer access after free client expects buffer to be free if free_buffer is called, but if omx is in executing state free buffer call will error out. When async thread tries to copy data to client buffer which is already freed,it leads to crash. Added a bitmask to avoid copy to buffer after free. Bug: 36130225 CRs-Fixed: 2106434 Author: Uma Mehta Change-Id: Id439aac54ee64a65ea68b6431a9f5150255a6980 --- .../vidc/venc/inc/omx_video_base.h | 1 + .../vidc/venc/src/omx_video_base.cpp | 18 ++++++++++++------ .../vidc/venc/src/omx_video_encoder.cpp | 7 ++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_base.h b/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_base.h index 1a537e4b..8fc78ce1 100644 --- a/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_base.h +++ b/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_base.h @@ -659,6 +659,7 @@ class omx_video: public qc_omx_component int pending_output_buffers; uint64_t m_out_bm_count; + uint64_t m_client_out_bm_count; uint64_t m_inp_bm_count; uint64_t m_flags; uint64_t m_etb_count; diff --git a/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp b/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp index fa6b08fb..abbcea34 100644 --- a/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp +++ b/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp @@ -295,6 +295,7 @@ omx_video::omx_video(): pending_input_buffers(0), pending_output_buffers(0), m_out_bm_count(0), + m_client_out_bm_count(0), m_inp_bm_count(0), m_flags(0), m_etb_count(0), @@ -2598,7 +2599,6 @@ OMX_ERRORTYPE omx_video::use_output_buffer( return OMX_ErrorBadParameter; } - auto_lock l(m_buf_lock); if (!m_out_mem_ptr) { output_use_buffer = true; int nBufHdrSize = 0; @@ -2749,6 +2749,7 @@ OMX_ERRORTYPE omx_video::use_output_buffer( } BITMASK_SET(&m_out_bm_count,i); + BITMASK_SET(&m_client_out_bm_count,i); } else { DEBUG_PRINT_ERROR("ERROR: All o/p Buffers have been Used, invalid use_buf call for " "index = %u", i); @@ -2786,6 +2787,8 @@ OMX_ERRORTYPE omx_video::use_buffer( DEBUG_PRINT_ERROR("ERROR: Use Buffer in Invalid State"); return OMX_ErrorInvalidState; } + + auto_lock l(m_buf_lock); if (port == PORT_INDEX_IN) { eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer); } else if (port == PORT_INDEX_OUT) { @@ -2857,7 +2860,6 @@ OMX_ERRORTYPE omx_video::free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) } if (index < m_sInPortDef.nBufferCountActual && m_pInput_pmem) { - auto_lock l(m_lock); if (m_pInput_pmem[index].fd > 0 && input_use_buffer == false) { DEBUG_PRINT_LOW("FreeBuffer:: i/p AllocateBuffer case"); @@ -3369,7 +3371,7 @@ OMX_ERRORTYPE omx_video::allocate_buffer(OMX_IN OMX_HANDLETYPE h DEBUG_PRINT_ERROR("ERROR: Allocate Buf in Invalid State"); return OMX_ErrorInvalidState; } - + auto_lock l(m_buf_lock); // What if the client calls again. if (port == PORT_INDEX_IN) { #ifdef _ANDROID_ICS_ @@ -3440,7 +3442,12 @@ OMX_ERRORTYPE omx_video::free_buffer(OMX_IN OMX_HANDLETYPE hComp, unsigned int nPortIndex; DEBUG_PRINT_LOW("In for encoder free_buffer"); - + auto_lock l(m_buf_lock); + if (port == PORT_INDEX_OUT) { //client called freebuffer, clearing client buffer bitmask right away to avoid use after free + nPortIndex = buffer - (OMX_BUFFERHEADERTYPE*)m_out_mem_ptr; + if(BITMASK_PRESENT(&m_client_out_bm_count, nPortIndex)) + BITMASK_CLEAR(&m_client_out_bm_count,nPortIndex); + } if (m_state == OMX_StateIdle && (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) { DEBUG_PRINT_LOW(" free buffer while Component in Loading pending"); @@ -3517,7 +3524,6 @@ OMX_ERRORTYPE omx_video::free_buffer(OMX_IN OMX_HANDLETYPE hComp, nPortIndex, (unsigned int)m_sOutPortDef.nBufferCountActual); if (nPortIndex < m_sOutPortDef.nBufferCountActual && BITMASK_PRESENT(&m_out_bm_count, nPortIndex)) { - auto_lock l(m_buf_lock); // Clear the bit associated with it. BITMASK_CLEAR(&m_out_bm_count,nPortIndex); m_sOutPortDef.bPopulated = OMX_FALSE; @@ -3778,7 +3784,7 @@ OMX_ERRORTYPE omx_video::empty_this_buffer_proxy(OMX_IN OMX_HANDLETYPE hComp, { DEBUG_PRINT_LOW("Heap UseBuffer case, so memcpy the data"); - auto_lock l(m_lock); + auto_lock l(m_buf_lock); pmem_data_buf = (OMX_U8 *)m_pInput_pmem[nBufIndex].buffer; if (pmem_data_buf) { memcpy (pmem_data_buf, (buffer->pBuffer + buffer->nOffset), diff --git a/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp b/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp index b09400a0..1d7c8bac 100644 --- a/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp +++ b/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp @@ -2098,11 +2098,15 @@ OMX_ERRORTYPE omx_venc::component_deinit(OMX_IN OMX_HANDLETYPE hComp) DEBUG_PRINT_ERROR("WARNING:Rxd DeInit,OMX not in LOADED state %d",\ m_state); } + + auto_lock l(m_buf_lock); if (m_out_mem_ptr) { DEBUG_PRINT_LOW("Freeing the Output Memory"); for (i=0; i< m_sOutPortDef.nBufferCountActual; i++ ) { if (BITMASK_PRESENT(&m_out_bm_count, i)) { BITMASK_CLEAR(&m_out_bm_count, i); + if (BITMASK_PRESENT(&m_client_out_bm_count, i)) + BITMASK_CLEAR(&m_client_out_bm_count, i); free_output_buffer (&m_out_mem_ptr[i]); } @@ -2449,7 +2453,8 @@ int omx_venc::async_message_process (void *context, void* message) omxhdr->nFlags = m_sVenc_msg->buf.flags; /*Use buffer case*/ - if (omx->output_use_buffer && !omx->m_use_output_pmem && !omx->is_secure_session()) { + if (BITMASK_PRESENT(&(omx->m_client_out_bm_count), bufIndex) && + omx->output_use_buffer && !omx->m_use_output_pmem && !omx->is_secure_session()) { DEBUG_PRINT_LOW("memcpy() for o/p Heap UseBuffer"); memcpy(omxhdr->pBuffer, (m_sVenc_msg->buf.ptrbuffer),