Simple and effective method: mmap and remap_pfn_range
0x00 background
As we all know, modern operating systems use a complex method of memory management for the sake of security and overall planning of hardware, resulting in the concept of physical addresses, logical addresses, virtual addresses, and so on. This part of the content is not mentioned in detail, simply
The kernel and user-State processes have different logical address spaces. The page on which the kernel is located has higher permissions. User Permissions cannot be changed at will. Otherwise, you cannot change your permissions.
However, this is not a completely airtight wall, and the kernel provides a variety of ways for users to exchange data. If you need to exchange a large amount of data in a short period of time and have real-time requirements, linux kernel provides a simple and effective method: Shared Memory-mmap syscall.
The principle is also very simple. The physical page mapped to the kernel is also mapped to the user process and the permission attribute is modified. In this case, the two memories belonging to different address spaces actually correspond to the same physical page. One Party modifies the data and the other party can see the changes in real time.
General application scenarios are embedded devices, such as refresh the LED display screen and record a large amount of sensor data. This requires developers to implement mmap logic simultaneously in their own drivers and user code.
First, provide the following interface functions in the Custom driver file:
The kernel function remap_pfn_range () maps the page to the user process as needed.
See: http://www.makelinux.net/ldd3/chp-15-sect-2
Then, in the user program, you can simply use this custom mmap function to create page ing for the purpose of sharing memory.
0x01 Vulnerability
The simpler and easier it is to use, the more prone to problems.
The remap_pfn_range () function does not check the input parameters. It maps the page to the user State based on the memory start position, length, and access permission. All these checks must be completed by the mmap function implemented in the Custom driver.
The above is an example provided in the official documentation. Of course, this Code cannot be used directly in the product!
For example, the following product implementation:
Https://github.com/rajamalw/galaxy-s5360/blob/master/modules/drivers/video/hantro/ldriver/kernel_26x/hx170dec.c
#!cpp/*------------------------------------------------------------------------------ Function name : hx170dec_mmap Description : mmap method Return type : int------------------------------------------------------------------------------*/static int hx170dec_mmap(struct file *file, struct vm_area_struct *vma){ if (vma->vm_end - vma->vm_start > ((DEC_IO_SIZE + PAGE_SIZE - 1) & PAGE_MASK)) return -EINVAL; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ if (remap_pfn_range(vma, vma->vm_start, (DEC_IO_BASE >> PAGE_SHIFT), vma->vm_end - vma->vm_start, vma->vm_page_prot)) { pr_err("%s(): remap_pfn_range() failed\n", __FUNCTION__); return -EINVAL; } return 0;}
I only checked the application length slightly, and others naturally believed in the user code.
Serious consequences:
Https://labs.mwrinfosecurity.com/system/assets/762/original/mwri_advisory_huawei_driver-root-exploit.pdf WooYun: MTK camera kernel drive defects resulting in permission escalation WooYun: Huawei's latest Ascend P6 mobile phone kernel defects resulting in local permission escalation WooYun: Huawei haisi platform decoder driver defects and improper permission setup
Let's take a look at a better example:
Https://github.com/nirodg/android_device_huawei_hwp7/blob/master/kernel/huawei/hwp7/drivers/hik3/g1dec/hx170dec.c
#!cppstatic int hx170dec_mmap(struct file *file, struct vm_area_struct *vma){ unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; int retval = 0; unsigned long pyhs_start = vma->vm_pgoff << PAGE_SHIFT; unsigned long pyhs_end = pyhs_start + size; if(!(pyhs_start >= hisi_reserved_codec_phymem//not codec memory && pyhs_end <= hisi_reserved_codec_phymem + HISI_MEM_CODEC_SIZE) && !(pyhs_start >= hx170dec_data.iobaseaddr//not io address && pyhs_end <= hx170dec_data.iobaseaddr + hx170dec_data.iosize)) { printk(KERN_ERR "%s(%d) failed map:0x%lx-0x%lx\n", __FUNCTION__, __LINE__, pyhs_start, pyhs_end); return -EFAULT; } /* make buffers write-thru cacheable */ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); if (remap_pfn_range(vma, start, vma->vm_pgoff, size, vma->vm_page_prot)) retval = -ENOBUFS; return retval;}
Before calling the remap_pfn_range function, we performed a number of checks to limit the start and end positions of the requested address.
0x02 others
The overall security architecture of the android system is very complex and huge. The vulnerabilities mentioned above cannot be exploited to escalate permissions if they happen in a driver. Because other applications do not have the permission to access the problematic driver. However, if the access permission of the driver fails, for example:
So the continuous mistakes are actually 666 for attackers.
0x03 conclusion
The security issues discussed in this article often occur in the equipment of a manufacturer, and the time span is several years. I hope your factory can improve its security awareness, work overtime, and pay attention to the code quality.