登山则情满于山,观海则意溢于海。这篇文章主要讲述Android驱动中的remap_pfn_range()校验漏洞(CVE-2013-2596)相关的知识,希望能为你提供帮助。
简单介绍当然类似函数还有io_remap_pfn_range()。
remap_pfn_range() 为用户态提供了一种手段访问内核地址空间。它通过新页表,将一块内核物理内存映射到用户态进程空间。
remap_pfn_range() 函数的原型如下:
int remap_pfn_range(struct vm_area_struct *vma,
unsigned long virt_addr,
unsigned long pfn,
unsigned long size,
pgprot_t prot);
其中
unsigned long pfn 表示映射的物理起始地址
unsigned long size 表示映射的内存大小
remap_pfn_range() 函数内部没有对这两个参数进行控制。可以想象,当pfn传入内核态物理起始地址(0xc0000000),size传入内核空间大小(1G),便可以将整个内核映射到用户态,任意访问修改。
在一种常用提权方式中,便可以利用这种能力将fsync()地址修改为shellcode地址,实现提权。
因此,在编写驱动mmap接口代码时,***一定要准确的校验remap_pfn_range()的pfn和size参数。***
一个CVE案例android_rooting_tools项目中,包含了一个这样的实例。libfb_mem_exploit工程包含了CVE-2013-2596的漏洞利用代码,这是高通图形设备驱动中的一个漏洞,由于整数溢出,导致绕过了remap_pfn_range()参数校验逻辑。
下面代码注释位置,是漏洞根源:
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
{
struct fb_info *info = file_fb_info(file);
struct fb_ops *fb;
unsigned long off;
unsigned long start;
u32 len;
if (!info)
return -ENODEV;
if (vma->
vm_pgoff >
(~0UL >
>
PAGE_SHIFT))
return -EINVAL;
off = vma->
vm_pgoff <
<
PAGE_SHIFT;
fb = info->
fbops;
if (!fb)
return -ENODEV;
mutex_lock(&
info->
mm_lock);
if (fb->
fb_mmap) {
int res;
res = fb->
fb_mmap(info, vma);
mutex_unlock(&
info->
mm_lock);
return res;
} /* frame buffer memory */
start = info->
fix.smem_start;
len = PAGE_ALIGN((start &
~PAGE_MASK) + info->
fix.smem_len);
if (off >
= len) {
/* memory mapped io */
off -= len;
if (info->
var.accel_flags) {
mutex_unlock(&
info->
mm_lock);
return -EINVAL;
}
start = info->
fix.mmio_start;
len = PAGE_ALIGN((start &
~PAGE_MASK) + info->
fix.mmio_len);
}
mutex_unlock(&
info->
mm_lock);
start &
= PAGE_MASK;
/* 同时校验pfn与size参数,整数溢出将导致校验绕过 */
if ((vma->
vm_end - vma->
vm_start + off) >
len)
return -EINVAL;
off += start;
vma->
vm_pgoff = off >
>
PAGE_SHIFT;
/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by io_remap_pfn_range()*/
vma->
vm_page_prot = vm_get_page_prot(vma->
vm_flags);
fb_pgprotect(file, vma, off);
if (io_remap_pfn_range(vma, vma->
vm_start, off >
>
PAGE_SHIFT,
vma->
vm_end - vma->
vm_start, vma->
vm_page_prot))
return -EAGAIN;
return 0;
}
用户态mmap调用与fb_mmap的参数关系如下:
prot——vma->
vma_page_prot
offset——vma->
vma_pgoff
length——vma->
end - vma->
start
分析构造的PoC:
mapped_address = mmap((void *)MAPPED_BASE, (0x100000000 - kernel_phys_address),
PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED,
*fd, kernel_phys_address + info.smem_len);
以下是漏洞代码的校验逻辑:
start = info->
fix.smem_start;
off = vma->
vm_pgoff <
<
PAGE_SHIFT;
len = PAGE_ALIGN((start &
~PAGE_MASK) + info->
fix.smem_len);
if ((vma->
vm_end - vma->
vm_start + off) >
len)
return -EINVAL;
vma-> vm_end - vma-> vm_start + off = (0x100000000 - kernel_phys_address) + (kernel_phys_address + info.smem_len) = 0x100000000 + info.smem_len
由于整数溢出,0x100000000 + info.smem_len = info.smem_len > len 恒不成立,即绕过参数校验。
下面代码直观感受整数溢出的效果:
[email
protected]:~/Linux_prj/PoC$ cat integer_overflow.c
#include <
stdio.h>
#include <
stdlib.h>
int main ()
{
unsigned long len = 126;
unsigned long base = 0x100000000;
printf ("%lu
", base+len);
return 0;
}
[email
protected]:~/Linux_prj/PoC$ ./integer_overflow
126
安全建议用户态
- 设置合适的设备访问权限 (“/dev/graphics/fb0”)
- 配置SEAndroid 文件访问策略
- 做好参数校验(pfn和size),尤其考虑好整数溢出导致校验逻辑绕过的问题
推荐阅读
- Android Studio NDK开发环境搭建
- Win 8系统下怎样打开/关闭Bing联机搜索?【图文详细教程】
- 如何处理Win8系统打开页面时提示未响应问题?
- Win8系统下打开应用商店提示脱机的3种处理技巧
- 笔记本Win8系统弹出“文字换转出错”提示怎样办
- win8系统文件失去该如何找到?
- 笔记本win8系统关闭鼠标单击锁定技巧的办法
- Win8系统中无线零设置服务的打开办法
- 笔记本Win 8没有“连接到Microsoft账号”怎样办