2023.09.11 补 2023.09.09

CVE-2021-39675 A-205729183 EoP 严重 12

patch

分析

很明显,没有判断传入的size的上限,可能导致OOB Write。

/*******************************************************************************
**
** Function         GKI_getbuf
**
** Description      Called by an application to get a free buffer which
**                  is of size greater or equal to the requested size.
**
**                  Note: This routine only takes buffers from public pools.
**                        It will not use any buffers from pools
**                        marked GKI_RESTRICTED_POOL.
**
** Parameters       size - (input) number of bytes needed.
**
** Returns          A pointer to the buffer, or NULL if none available
**
*******************************************************************************/
void* GKI_getbuf(uint16_t size) {
  BUFFER_HDR_T* p_hdr;
  FREE_QUEUE_T* Q;
#if defined(DYN_ALLOC) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
  if (size == 0) { // 没有判断size的上限,可能导致越界写
    LOG(ERROR) << StringPrintf("getbuf: Size is zero");
#ifndef DYN_ALLOC
    abort();
#else
    return (nullptr);
#endif
  }
  size = ALIGN_POOL(size);
  size_t total_sz = size + sizeof(BUFFER_HDR_T)
#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
                    + sizeof(uint32_t);
#else
      ;
#endif
  p_hdr = (BUFFER_HDR_T*)GKI_os_malloc(total_sz);
  if (!p_hdr) {
    LOG(ERROR) << StringPrintf("unable to allocate buffer!!!!!");
#ifndef DYN_ALLOC
    abort();
#else
    return (nullptr);
#endif
  }
  memset(p_hdr, 0, total_sz);
#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
  *(uint32_t*)((uint8_t*)p_hdr + BUFFER_HDR_SIZE + size) = MAGIC_NO;
#endif
  p_hdr->task_id = GKI_get_taskid();
  p_hdr->status = BUF_STATUS_UNLINKED;
  p_hdr->p_next = nullptr;
  p_hdr->Type = 0;
  p_hdr->q_id = 0;
  p_hdr->size = size;
  GKI_disable();
  Q = &gki_cb.com.freeq[p_hdr->q_id];
  if (++Q->cur_cnt > Q->max_cnt) Q->max_cnt = Q->cur_cnt;
  GKI_enable();
  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "%s %p %d:%d", __func__, ((uint8_t*)p_hdr + BUFFER_HDR_SIZE), Q->cur_cnt,
      Q->max_cnt);
  UNUSED(gki_alloc_free_queue);
  return (void*)((uint8_t*)p_hdr + BUFFER_HDR_SIZE);
#else
  uint8_t i;
  tGKI_COM_CB* p_cb = &gki_cb.com;
  if (size == 0) {
    GKI_exception(GKI_ERROR_BUF_SIZE_ZERO, "getbuf: Size is zero");
    return (nullptr);
  }
  /* Find the first buffer pool that is public that can hold the desired size */
  for (i = 0; i < p_cb->curr_total_no_of_pools; i++) {
    if (size <= p_cb->freeq[p_cb->pool_list[i]].size) break;
  }
  if (i == p_cb->curr_total_no_of_pools) {
    GKI_exception(GKI_ERROR_BUF_SIZE_TOOBIG, "getbuf: Size is too big");
    return (nullptr);
  }
  /* Make sure the buffers aren't disturbed til finished with allocation */
  GKI_disable();
  /* search the public buffer pools that are big enough to hold the size
   * until a free buffer is found */
  for (; i < p_cb->curr_total_no_of_pools; i++) {
    /* Only look at PUBLIC buffer pools (bypass RESTRICTED pools) */
    if (((uint16_t)1 << p_cb->pool_list[i]) & p_cb->pool_access_mask) continue;
    Q = &p_cb->freeq[p_cb->pool_list[i]];
    if (Q->cur_cnt < Q->total) {
      if (Q->p_first == nullptr && gki_alloc_free_queue(i) != true) {
        LOG(ERROR) << StringPrintf("out of buffer");
        GKI_enable();
        return nullptr;
      }
      if (Q->p_first == nullptr) {
        /* gki_alloc_free_queue() failed to alloc memory */
        LOG(ERROR) << StringPrintf("fail alloc free queue");
        GKI_enable();
        return nullptr;
      }
      p_hdr = Q->p_first;
      Q->p_first = p_hdr->p_next;
      if (!Q->p_first) Q->p_last = nullptr;
      if (++Q->cur_cnt > Q->max_cnt) Q->max_cnt = Q->cur_cnt;
      GKI_enable();
      p_hdr->task_id = GKI_get_taskid();
      p_hdr->status = BUF_STATUS_UNLINKED;
      p_hdr->p_next = nullptr;
      p_hdr->Type = 0;
      return ((void*)((uint8_t*)p_hdr + BUFFER_HDR_SIZE));
    }
  }
  LOG(ERROR) << StringPrintf("unable to allocate buffer!!!!!");
  GKI_enable();
  return (nullptr);
#endif
}

PoC

#include "../includes/common.h"
#include "gki.h"

int main() {
    return (GKI_getbuf(USHRT_MAX) == nullptr) ? EXIT_SUCCESS : EXIT_VULNERABLE;
}