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;
}