CVE-2021-0870 NFC竟也存在高危漏洞?看他如何分析( 三 )


函数用来发送GKI ()消息,
将event从一个task发送给另一个task,任务之间使用event数据结构的数据包,经安卓的进行消息传递.是谷歌专门为供应商设计的进程间通信框架,独立于安卓系统的存在,是从8.0以后引入的新机制 。
执行完后,除了测试框架调用Test的主线程外,进程中会多出两个线程,这两个线程就是两个task,可近似理解为一个是NFCC,另一个充当客户端,这两个线程之间互相发数据包交互 。作为服务端的task维护了一个命令队列,里面存放要被执行的命令,通过ueue去检查队列里有没有命令,如果有就去执行 。是这个事件处理消息的主循环 。环解析命令事件并执行相应的回调函数 。代码如下, 前一个if半部分负责处理初始化,后一个if是主循环:
uint32_t nfc_task(__attribute__((unused)) uint32_t arg) {.../* main loop */while (true) {event = GKI_wait(0xFFFF, 0);.../* Handle NFC_TASK_EVT_TRANSPORT_READY from NFC HAL */if (event & NFC_TASK_EVT_TRANSPORT_READY) {...nfc_set_state(NFC_STATE_CORE_INIT);nci_snd_core_reset(NCI_RESET_TYPE_RESET_CFG);}if (event & NFC_MBOX_EVT_MASK) {/* Process all incoming NCI messages */while ((p_msg = (NFC_HDR*)GKI_read_mbox(NFC_MBOX_ID)) != nullptr) {free_buf = true;/* Determine the input message type. */switch (p_msg->event & NFC_EVT_MASK) {case BT_EVT_TO_NFC_NCI:free_buf = nfc_ncif_process_event(p_msg);break;case BT_EVT_TO_START_TIMER:/* Start nfc_task 1-sec resolution timer */GKI_start_timer(NFC_TIMER_ID, GKI_SECS_TO_TICKS(1), true);break;case BT_EVT_TO_START_QUICK_TIMER:/* Quick-timer is required for LLCP */GKI_start_timer(NFC_QUICK_TIMER_ID,((GKI_SECS_TO_TICKS(1) / QUICK_TIMER_TICKS_PER_SEC)), true);break;case BT_EVT_TO_NFC_MSGS:nfc_main_handle_hal_evt((tNFC_HAL_EVT_MSG*)p_msg);break;default:DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("nfc_task: unhandle mbox message, event=x", p_msg->event);break;}if (free_buf) {GKI_freebuf(p_msg);}}}...}
Part2
第二部分代码如下所示:
std::vector reset_core = {0x1, 0x29, 0x20};g_callback_tracker->SimulatePacketArrival(NCI_MT_NTF, 0, NCI_GID_CORE, NCI_MSG_CORE_RESET, reset_core.data(),reset_core.size());{std::unique_lock reset_done_lock(cv_mutex);reset_done_cv.wait(reset_done_lock);}
l是poc调用频率最高的函数,模拟了从task之间数据交互的过程。
task之间使用NCI数据包通信,NCI数据包的格式简要概述为头部,共3字节 。
/* NCI Command and Notification Format:* 3 byte message header:* byte 0: MT PBF GID* byte 1: OID* byte 2: Message Length *//* MT: Message Type (byte 0) */
l如何构造数据包呢?以它第一次被调用为例:
SimulatePacketArrival(NCI_MT_NTF, 0, NCI_GID_CORE, NCI_MSG_CORE_RESET, reset_core.data(),reset_core.size())
对比他的函数原型:
void SimulatePacketArrival(uint8_t mt, uint8_t pbf, uint8_t gid,uint8_t opcode, uint8_t* data, size_t size)
可知mt->,pbf-> 0,gid->,->,data->.data(),size->.size(),std::-> {0x1, 0x29, 0x20};
先构造前三个组成头部,然后在末尾插入数据 。
std::vector buffer(3);buffer[0] = (mt << NCI_MT_SHIFT) | (pbf << NCI_PBF_SHIFT) | gid;//第一个8位,buffer[1] = (mt == NCI_MT_DATA) ? 0 : opcode;//第二个8位buffer[2] = static_cast(size);//第三个8位buffer.insert(buffer.end(), data, data + size);//尾部附加的实际数据是{0x1, 0x29, 0x20}data_callback_(buffer.size(), buffer.data());
接着调用函数发送数据给另一个task 。
每一次l调用后面都有一个代码块,例如:
{std::unique_lock reset_done_lock(cv_mutex);reset_done_cv.wait(reset_done_lock);}
是一个条件变量,条件变量是C++11引入的一种同步机制 。调用.wait时会将线程挂起,直到其他线程调用是才解除阻塞继续执行,合理运用条件变量可以实现不同线程之间的同步 。