漏洞原理总结:在函数nfc_ncif_proc_get_routing()
里,直接获取数据作为长度进行数组拷贝,读取的类型是uint8_t
,最大是255
,拷贝的数组定义长度125
,直接溢出
官方描述:In nfc_ncif_proc_get_routing of nfc_ncif.cc, there is a possible out of bounds write due to a missing bounds check. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is not needed for exploitation.
官方描述翻译:函数nfc_ncif.cc - nfc_ncif_proc_get_routing()
里,因为缺少边界检查,存在一个越界写,这可以造成提权并且无需额外的执行权限,利用这个漏洞也不需要用户交互
CVE 参考编号 类型 严重程度 已更新的 AOSP 版本 7.0、7.1.1、7.1.2、8.0、8.1、9
补丁
https://android.googlesource.com/platform/system/nfc/+/71764b791f262491e3f628c14ce3949863dd6058
Copy Prevent OOB error in nfc_ncif_proc_get_routing ()
Test: Tag reading; Card Emulation
Bug: 117554809
Change - Id: Ib49af2eadf870f030a6cddeec390dc498bd5078c
(cherry picked from commit ded496ea745656018dda505c23726b4304180c38)
diff -- git a / src / nfc / nfc / nfc_ncif . cc b / src / nfc / nfc / nfc_ncif . cc
index 93666e0..6d6607d 100644
--- a / src / nfc / nfc / nfc_ncif . cc
+++ b / src / nfc / nfc / nfc_ncif . cc
@@ - 25 , 6 + 25 , 7 @@
***************************************************************************** */
#include <android-base/stringprintf.h>
#include <base/logging.h>
+ #include < log / log . h >
#include <metricslogger/metrics_logger.h>
#include "nfc_target.h"
@@ - 1235 , 8 + 1236 , 13 @@
for (yy = 0 ; yy < evt_data . num_tlvs; yy ++ ) {
tl = * (p + 1 );
tl += NFC_TL_SIZE;
- STREAM_TO_ARRAY (pn , p , tl);
evt_data . tlv_size += tl;
+ if ( evt_data . tlv_size > NFC_MAX_EE_TLV_SIZE) {
+ android_errorWriteLog ( 0x 534e4554 , "117554809" );
+ LOG (ERROR) << __func__ << "Invalid data format" ;
+ return ;
+ }
+ STREAM_TO_ARRAY (pn , p , tl);
pn += tl;
}
tNFC_RESPONSE nfc_response;
入口简单的取值判断分支,最后调用到nci_proc_rf_management_ntf()
Copy #define NCI_MT_MASK 0x E0
#define NCI_MT_SHIFT 5
#define NCI_PBF_MASK 0x 10
#define NCI_PBF_SHIFT 4
#define NCI_GID_MASK 0x 0F
#define NCI_OID_MASK 0x 3F
/* parse byte0 of NCI packet */
#define NCI_MSG_PRS_HDR0 (p , mt , pbf , gid) \
mt = ( * (p) & NCI_MT_MASK) >> NCI_MT_SHIFT; \
(pbf) = ( * (p) & NCI_PBF_MASK) >> NCI_PBF_SHIFT; \
(gid) = * (p) ++ & NCI_GID_MASK;
/*******************************************************************************
**
** Function nfc_ncif_process_event
**
** Description This function is called to process the
** data/response/notification from NFCC
**
** Returns TRUE if need to free buffer
**
*******************************************************************************/
bool nfc_ncif_process_event ( NFC_HDR * p_msg) {
uint8_t mt , pbf , gid , * p , * pp;
bool free = true ;
uint8_t oid;
uint8_t * p_old , old_gid , old_oid , old_mt;
p = ( uint8_t* )(p_msg + 1 ) + p_msg -> offset;
pp = p;
NCI_MSG_PRS_HDR0 (pp , mt , pbf , gid);
oid = (( * pp) & NCI_OID_MASK); // oid = p[1] & NCI_OID_MASK
if ( nfc_cb . rawVsCbflag == true &&
nfc_ncif_proc_proprietary_rsp (mt , gid , oid) == true ) {
nci_proc_prop_raw_vs_rsp (p_msg);
nfc_cb . rawVsCbflag = false ;
return free;
}
nfcsnoop_capture (p_msg , true );
switch (mt) {
...
case NCI_MT_NTF :
DLOG_IF (INFO , nfc_debug_enabled)
<< StringPrintf ( "NFC received ntf gid: %d " , gid);
switch (gid) {
...
case NCI_GID_RF_MANAGE : /* 0001b NCI Discovery group */
nci_proc_rf_management_ntf (p_msg);
break ;
...
}
break ;
}
return (free);
}
获取op_code
,当op_code
为NCI_MSG_RF_GET_ROUTING
时,调用nfc_ncif_proc_get_routing()
,传入的缓冲区指针指向p[3]
,len
字段为p[2]
,这俩参数未做判断
Copy #define NCI_OID_MASK 0x 3F
/* parse byte1 of NCI Cmd/Ntf */
#define NCI_MSG_PRS_HDR1 (p , oid) \
(oid) = ( * (p) & NCI_OID_MASK); \
(p) ++ ;
/*******************************************************************************
**
** Function nci_proc_rf_management_ntf
**
** Description Process NCI notifications in the RF Management group
**
** Returns void
**
*******************************************************************************/
void nci_proc_rf_management_ntf ( NFC_HDR * p_msg) {
uint8_t* p;
uint8_t * pp , len , op_code;
/* find the start of the NCI message and parse the NCI header */
p = ( uint8_t* )(p_msg + 1 ) + p_msg -> offset; // 取用户传入的Buffer
pp = p + 1 ; // pp = p[1]
NCI_MSG_PRS_HDR1 (pp , op_code); // op_code = p[1] & NCI_OID_MASK
len = * pp ++ ; // len = p[2],获取完后pp指向p[3]
switch (op_code) {
...
#if ( NFC_NFCEE_INCLUDED == TRUE )
#if ( NFC_RW_ONLY == FALSE )
case NCI_MSG_RF_GET_ROUTING :
nfc_ncif_proc_get_routing (pp , len); // (p[3], p[2])
break ;
...
}
}
获取的tl
为p[8]
,然后将tl
加2,tl
的类型是uint8_t
,最大是255
,加上2之后就是257
,evt_data.param_tlvs
定义的长度为125
,所以拷贝数组的时候直接溢出
Copy #define NFC_MAX_EE_TLV_SIZE 150
typedef struct {
...
uint8_t param_tlvs [NFC_MAX_EE_TLV_SIZE]; /* the TLVs */
} tNFC_GET_ROUTING_REVT ;
/*******************************************************************************
**
** Function nfc_ncif_proc_get_routing
**
** Description This function is called to process get routing notification
**
** Returns void
**
*******************************************************************************/
void nfc_ncif_proc_get_routing ( uint8_t* p ,
__attribute__ ((unused)) uint8_t len) {
tNFC_GET_ROUTING_REVT evt_data;
uint8_t more , num_entries , xx , yy , * pn , tl;
tNFC_STATUS status = NFC_STATUS_CONTINUE;
if ( nfc_cb . p_resp_cback) {
more = * p ++ ; // more = p[3]
num_entries = * p ++ ; // num_entries = p[4]
for (xx = 0 ; xx < num_entries; xx ++ ) { // 这里可能存在多个entry
if ((more == false ) && (xx == (num_entries - 1 ))) status = NFC_STATUS_OK;
evt_data . status = (tNFC_STATUS)status;
evt_data . nfcee_id = * p ++ ; // evt_data.nfcee_id = p[5]
evt_data . num_tlvs = * p ++ ; // evt_data.num_tlvs = p[6]
evt_data . tlv_size = 0 ;
pn = evt_data . param_tlvs; // 定义的数组长度为150
for (yy = 0 ; yy < evt_data . num_tlvs; yy ++ ) {
tl = * (p + 1 ); // tl = p[8]
tl += NFC_TL_SIZE; // #define NFC_TL_SIZE 2
STREAM_TO_ARRAY (pn , p , tl); // tl的值最大为(255 + 2),但是数组长度定义为150,存在越界写
evt_data . tlv_size += tl;
pn += tl;
}
tNFC_RESPONSE nfc_response;
nfc_response . get_routing = evt_data;
( * nfc_cb . p_resp_cback)(NFC_GET_ROUTING_REVT , & nfc_response);
}
}
}
补丁所做的就是在拷贝前做好evt_data.tlv_size
的判断,这个字段表示当前已经拷贝的长度
Copy for (yy = 0 ; yy < evt_data . num_tlvs; yy ++ ) {
tl = * (p + 1 );
tl += NFC_TL_SIZE;
- STREAM_TO_ARRAY (pn , p , tl);
evt_data . tlv_size += tl;
+ if ( evt_data . tlv_size > NFC_MAX_EE_TLV_SIZE) {
+ android_errorWriteLog ( 0x 534e4554 , "117554809" );
+ LOG (ERROR) << __func__ << "Invalid data format" ;
+ return ;
+ }
+ STREAM_TO_ARRAY (pn , p , tl);
pn += tl;
}
tNFC_RESPONSE nfc_response;
Last updated 10 months ago