华为TrustZone TEE_EID漏洞
此通报包含有关以下漏洞的信息:
- CVE-2021-40028 漏洞CVE-2021-40028 Encap_tlv_for_hash_zip 函数中的 OOB 访问
- CVE-2021-40018 漏洞 get_sec_image_zip 函数中的 OOB 访问
- CVE-2021-40021 漏洞 check_xxx_params函数中的参数指针信息泄漏
- CVE-2021-40025 漏洞 堆指针 eid_malloc、eid_free、malloc_eid_buffer 和 free_eid_buffer 函数中的信息泄漏
函数中的 OOB 访问get_sec_image_zip
¶
函数中有一个 OOB 访问:get_sec_image_zip
int
get_sec_image_zip
(
void
*
ibuf0_addr
,
unsigned
int
*
ibuf0_20028
,
unsigned
int
*
ibuf0_20038
,
void
*
obuf3_addr
)
{
// [...]
img_buf
=
g_img_buf
;
// [...]
for
(
int
x
=
ibuf0_20028
[
0
];
x
<=
ibuf0_20028
[
1
];
x
++
)
{
for
(
int
y
=
ibuf0_20028
[
2
];
y
<=
ibuf0_20028
[
3
];
y
++
)
{
*
(
uint8_t
*
)(
eid_buf
.
addr
+
...)
=
*
(
uint8_t
*
)(
img_buf
+
x
*
0x1E0
+
y
);
}
}
// [...]
}
g_img_buf
存储在局部变量中,然后在许多循环中使用该变量,而无需检查它是否已被分配。如果确实未分配,则循环中的访问将是 OOB。img_buf
我们通过概念验证触发了此 bug,并获得了以下崩溃:
[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1f00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x0, fault_code: 0x92000006
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[TEE_EID] tid=40 is-idle=0 is-curr=0
[HM] state=BLOCKED@MEMFAULT sched.pol=0 prio=46 queued=1
[HM] aff[0]=ff
[HM] flags=1000 smc-switch=0 ca=7253 prefer-ca=7253
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <get_sec_image_zip+0x200/0x360>
[HM] <?>+0x0/0x0
[HM] <proc_sec_zip_cmd>+0x34/0x48
[HM] <tee_task_entry>+0x398/0xcd4
[HM] Dump task states END
[HM]
[HM] [TRACE][1212]pid=48 exit_status=130
函数中的 OOB 访问Encap_tlv_for_hash_zip
¶
这是函数中的另一个 OOB 访问:Encap_tlv_for_hash_zip
int
Encap_tlv_for_hash_zip
(
int
hash
,
int
hash_len
,
int
zip
,
int
zip_len
,
uint8_t
*
hash_tlv
)
{
// [...]
*
(
uint32_t
*
)(
hash_tlv
+
0
)
=
2
;
SLog
(
"%s: Tlv hash type = %u
n
"
,
"[Trace]"
,
2
);
*
(
uint32_t
*
)(
hash_tlv
+
4
)
=
hash_len
;
SLog
(
"%s: Tlv hash_len = %u
n
"
,
"[Trace]"
,
hash_len
);
if
(
memcpy_s
(
hash_tlv
+
8
,
0x1FFF8
,
hash
,
hash_len
))
{
SLog
(
"%s: memcpy_s err size is %d, len is %d
n
"
,
"[Error]"
,
0x1FFF8
,
hash_len
);
return
-1
;
}
printHexWithTag
(
"Sm3 hash"
,
hash
,
hash_len
);
*
(
uint32_t
*
)(
hash_tlv
+
hash_len
+
8
)
=
1
;
SLog
(
"%s: Tlv zip type = %u
n
"
,
"[Trace]"
,
1
);
*
(
uint32_t
*
)(
hash_tlv
+
hash_len
+
0xc
)
=
zip_len
;
SLog
(
"%s: Tlv zip_len = %u
n
"
,
"[Trace]"
,
zip_len
);
if
(
memcpy_s
(
hash_tlv
+
hash_len
+
0x10
,
0x1FFF0
-
hash_len
,
zip
,
zip_len
))
{
SLog
(
"%s: memcpy_s err size is %d, len is %d
n
"
,
"[Error]"
,
0x1FFF0
-
hash_len
,
zip_len
);
return
-1
;
}
return
hash_len
+
0x10
+
zip_len
;
}
的值上限为 0x1FFF8,因为第一个 。但对于介于 0x1FFF1 和 0x1FFF8 之间的值,可以观察到以下行为:hash_len
memcpy_s
hash_len
- TLV 类型 (1) 在偏移处的写入可以是 OOB
hash_len + 8
- TLV 长度 () 在偏移处的写入可以是 OOB
zip_len
hash_len + 0xC
- at 偏移量的目标可以是 OOB
memcpy_s
hash_len + 0x10
- ()的大小可以下溢
memcpy_s
0x1FFF0 - hash_len
该函数将检测负大小,因此无法利用此行为。TLV 类型和长度的 OOB 写入将发生越界,但它们不会使 trustlet/分配器崩溃。我们怀疑这是因为分配是 mmap 的,并且大小(包括元数据)是页面对齐的,导致分配后出现填充。memcpy_s
尽管如此,通过使用概念证明触发此错误,我们可以看到负大小 (-4),证明 TLV 类型和长度 OOB 写入访问:
[TEE_EID-1] [Trace]: ------ TA_InvokeCommandEntryPoint ------
[TEE_EID-1] [Trace]: Recived the commond, id is 9
[TEE_EID-1] [Trace]: Recived the unsec zip message
[TEE_EID-1] [Trace]: Into the proc_unsec_zip_cmd function
[TEE_EID-1] [Trace]: Malloc_eid_buffer, addr = 0x375f010, len = 131072
[TEE_EID-1] [Trace]: Tlv hash type = 2
[TEE_EID-1] [Trace]: Tlv hash_len = 131060
[TEE_EID-1] [Trace]: Tlv zip type = 1
[TEE_EID-1] [Trace]: Tlv zip_len = 4096
[TEE_EID-1] [Error]: memcpy_s err size is -4, len is 4096
[TEE_EID-1] [Error]: Encap_tlv_for_hash_zip failed!
[TEE_EID-1] [Trace]: Free_eid_buffer, addr = 0x375f010
函数中的参数指针信息泄漏check_xxx_params
¶
检查每个命令的输入参数的函数中存在信息泄漏,包括函数(在 0x71A8 处):check_common_params
unsigned
int
check_common_params
(
int
paramTypes
,
TEE_Param
*
params
)
{
// [...]
if
(
params
[
0
].
memref
.
size
!=
4
||
!
params
[
0
].
memref
.
buffer
)
{
SLog
(
"%s: Invalid param[0], size is %u, buffer address is %p
nn
"
,
"[Error]"
,
params
[
0
].
memref
.
size
,
params
[
0
].
memref
.
buffer
);
return
0xFFFF0006
;
}
// [...]
}
当参数缓冲区地址的大小不正确时,所有这些函数都会打印参数缓冲区地址。这将显示缓冲区始终映射在同一地址。下面是一个日志消息示例:
[TEE_EID-1] [Trace]: Recived the commond, id is 6
[TEE_EID-1] [Trace]: Recived the id info message
[TEE_EID-1] [Error]: Invalid param[3], size is 2056, buffer address is 0x70004000
堆指针 、 和 函数中的信息泄漏eid_malloc
eid_free
malloc_eid_buffer
free_eid_buffer
¶
分配和解除分配函数中存在信息泄漏,包括 、 、 和 :eid_malloc
eid_free
malloc_eid_buffer
free_eid_buffer
void
*
eid_malloc
(
int
len
,
int
hint
)
{
// [...]
addr
=
TEE_Malloc
(
len
,
hint
);
SLog
(
"%s: Eid_malloc, addr = %p, len = %u
n
"
,
"[Trace]"
,
addr
,
len
);
return
addr
;
}
void
eid_free
(
void
*
addr
)
{
SLog
(
"%s: Eid_free, addr = %p
n
"
,
"[Trace]"
,
addr
);
TEE_Free
(
addr
);
}
int
malloc_eid_buffer
(
eid_buffer_t
*
buf
,
int
size
)
{
// [...]
buf
->
addr
=
TEE_Malloc
(
size
,
0
);
// [...]
buf
->
size
=
size
;
SLog
(
"%s: Malloc_eid_buffer, addr = %p, len = %u
n
"
,
"[Trace]"
,
buf
->
addr
,
size
);
return
0
;
}
int
free_eid_buffer
(
eid_buffer_t
*
buf
)
{
// [...]
buf
->
size
=
0
;
SLog
(
"%s: Free_eid_buffer, addr = %p
n
"
,
"[Trace]"
,
buf
->
addr
);
return
TEE_Free
(
buf
->
addr
);
}
这些函数打印已分配/释放缓冲区的地址。在开发堆漏洞时,这可能是有用的信息。下面是一个日志消息示例:
[TEE_EID-1] [Trace]: Malloc_eid_buffer, addr = 0x375f010, len = 131072
...
[TEE_EID-1] [Trace]: Free_eid_buffer, addr = 0x375f010
受影响的设备¶
我们验证了这些漏洞是否影响了以下设备:
- 麒麟990:P40 专业版 (ELS)
请注意,其他型号可能已受到影响。
补丁¶
名字 | 严厉 | CVE漏洞 | 补丁 |
---|---|---|---|
函数中的 OOB 访问Encap_tlv_for_hash_zip |
危急 | CVE-2021-40028 漏洞CVE-2021-40028 | 2022 年 1 月 |
函数中的 OOB 访问get_sec_image_zip |
高 | CVE-2021-40018 漏洞 | 2022 年 1 月 |
函数中的参数指针信息泄漏check_xxx_params |
中等 | CVE-2021-40021 漏洞 | 2022 年 1 月 |
堆指针 、 和 函数中的信息泄漏eid_malloc eid_free malloc_eid_buffer free_eid_buffer |
中等 | CVE-2021-40025 漏洞 | 2022 年 1 月 |
时间线¶
- 2021年11月05日,华为PSIRT收到漏洞报告。
- 2021年11月16日 - 华为PSIRT确认该漏洞报告。
- 2022年1月1日 - 华为PSIRT表示,这些问题已在2022年1月的更新中修复。
- 从 2022 年 11 月 30 日至 2023 年 7 月 19 日 - 我们定期交换有关公告发布的信息。
原文始发于微信公众号(安全狗的自我修养):二进制漏洞分析-18.华为TrustZone TEE_EID漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论