Android 8.1 上 memcpy 一点有趣的东西

前言

这几天一直在看 CVE-2020-0022 的东西,不清楚的同学可以参考:

https://insinuator.net/2020/02/critical-bluetooth-vulnerability-in-android-cve-2020-0022/

代码不长,具体逻辑我就不在这里分析了,总而言之问题就是

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/hci/src/packet_fragmenter.cc b/hci/src/packet_fragmenter.cc
index 5036ed5..143fc23 100644
--- a/hci/src/packet_fragmenter.cc
+++ b/hci/src/packet_fragmenter.cc
@@ -221,7 +221,8 @@
"%s got packet which would exceed expected length of %d. "
"Truncating.",
__func__, partial_packet->len);
- packet->len = partial_packet->len - partial_packet->offset;
+ packet->len =
+ (partial_packet->len - partial_packet->offset) + packet->offset;
projected_offset = partial_packet->len;
}

当计算 packet->len = partial_packet->len - partial_packet->offset; 值的时候,可能计算出一个小的数,或者干脆是负数,导致在

image

后面拷贝的时候, 拷贝一个 负数长度的值,由于 memcpy 参数是无符号的,则导致拷贝一个大数

Android 8.1 memcpy 引起的一个小bug

在我和 @leommxj 测试的过程中,遇到一个坑,大致如图:

X0 是 dest ,X1是 src, X2是 size ,此时的size 明明是个负数,而且下溢后至少是一个很大的数,但是程序并没有崩溃。

引起 BUG 的原因

真的各种猜测不如看代码,所以我们把 libc.so 拿出来看了一下

image

重点在于:

image

此时 X0 是dest,Dest 取低位赋值给X9,然后

1
ADD X2, X2 ,X9

而此时的 X2 是 len,导致他整型上溢出,变成一个小的数字,例如 0xa

image

当进入下图逻辑时

image

此时 X2 为 0xA,进行下面的指令的时候

1
2
SUBS            X2, X2, #0x90
B.LS loc_1C8A8

由于此时 X2 为 0xA ,小于0x40,所以 此时条件为 小于

B. LS 则表示,当小于等于条件成立时候,为真,则跳转到 loc_1C8A8 处代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
loc_1C8A8
LDP X1, X2, [X4,#-0x40]
STP X6, X7, [X3,#0x10]
LDP X6, X7, [X4,#-0x30]
STP X8, X9, [X3,#0x20]
LDP X8, X9, [X4,#-0x20]
STP X10, X11, [X3,#0x30]
LDP X10, X11, [X4,#-0x10]
STP X12, X13, [X3,#0x40]
STP X1, X2, [X5,#-0x40]
STP X6, X7, [X5,#-0x30]
STP X8, X9, [X5,#-0x20]
STP X10, X11, [X5,#-0x10]
RET
; } // starts at 1C770

之后的代码逻辑直接就是 RET ,导致 并没有拷贝过长的内存,导致 crash。