简单介绍

当然类似函数还有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 恒不成立,即绕过参数校验。

下面代码直观感受整数溢出的效果:

zzy@ubuntu:~/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\n", base+len);
return 0;
}
zzy@ubuntu:~/Linux_prj/PoC$ ./integer_overflow
126

安全建议

用户态

  1. 设置合适的设备访问权限 (“/dev/graphics/fb0”)
  2. 配置SEAndroid 文件访问策略

内核态

  1. 做好参数校验(pfn和size),尤其考虑好整数溢出导致校验逻辑绕过的问题

Android驱动中的remap_pfn_range()校验漏洞(CVE-2013-2596)的更多相关文章

  1. Android开发中实现https校验

    在安卓开发中需要自己写代码实现校验公钥的功能 当然,  如果是自己服务器,就不用校验, 如果是别人的服务器,比如银行,就需要校验 在这里, 小编采用从github上下载的开源框架实现,在开源框架中添加 ...

  2. Android驱动中的Kconfig文件与Makefile文件

    内核源码树的目录下都有两个文档Kconfig(2.4版本是Config.in)和Makefile.分布到各目录的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文 ...

  3. Android平台上直接物理内存读写漏洞的那些事

    /* 本文章由 莫灰灰 编写,转载请注明出处. 作者:莫灰灰    邮箱: minzhenfei@163.com */ 通过mmap直接操作物理内存的漏洞应该算是比較常见的一类漏洞了,在2012年.2 ...

  4. Android安全之Https中间人攻击漏洞

    Android安全之Https中间人攻击漏洞 0X01 概述   HTTPS,是一种网络安全传输协议,利用SSL/TLS来对数据包进行加密,以提供对网络服务器的身份认证,保护交换数据的隐私与完整性. ...

  5. 初入android驱动开发之字符设备(一)

    大学毕业,初入公司,招进去的是android驱动开发工程师的岗位,那时候刚进去,首先学到的就是如何搭建kernel.android的编译环境,然后就是了解如何刷设备以及一些最基本的工具.如adb.fa ...

  6. Android驱动开发5-8章读书笔记

    Android驱动开发读书笔记                                                              第五章 S5PV210是一款32位处理器,具有 ...

  7. Android驱动开发前的准备

    最近看了一些Android驱动开发前需要知道的资料,收获很多,接下来就谈谈我自己的一些心得体会. Android在近几年时间发展迅速,已经成为智能手机操作系统的老大.不过,因为Android原生的代码 ...

  8. Android驱动开发前的准备(四)

    源代码的下载和编译 4.1 下载.编译和测试Android源代码 4.2下载和编译linux内核源代码 4.1.1 配置Android源代码下载环境 (1) 创建一个用于存放下载脚本文件的目录 # m ...

  9. Android开发中的输入合法性检验

    Why ? 合法性检查对于程序的健壮性具有重要作用.在Android开发中,良好的合法性检查设计机制可以使程序更加清晰,产生bug更少,交互更加友好. What ? 合法性检查的目的在于确定边界.对于 ...

随机推荐

  1. [转载]Python3编码问题详解

    原文:Python3的编码问题 Python3 最重要的一项改进之一就是解决了 Python2 中字符串与字符编码遗留下来的这个大坑.Python 编码为什么那么蛋疼?已经介绍过 Python2 字符 ...

  2. [LeetCode] 111. Minimum Depth of Binary Tree ☆(二叉树的最小深度)

    [Leetcode] Maximum and Minimum Depth of Binary Tree 二叉树的最小最大深度 (最小有3种解法) 描述 解析 递归深度优先搜索 当求最大深度时,我们只要 ...

  3. PAT-GPLT训练集 L2-001 紧急救援(最短路)

    PAT-GPLT训练集 L2-001 紧急救援 题目大意:求最短路的条数,最短路中的权重和的最大值和这条最短路的路线 分析:使用dijkstra算法求出最短路,并且对dijkstra算法进行变化,设起 ...

  4. Linux command stty

    Linux command stty reference: https://blog.csdn.net/lqxandroid2012/article/details/78929506 [Purpose ...

  5. redis客户端windows版中文乱码解决方案

    1.在cmd窗口,在redis-cli.exe 后加上--raw 2.修改cmd窗口编码 http://jingyan.baidu.com/article/e75aca85440f01142edac6 ...

  6. Yii验证码简单使用及

    控制器:(写了貌似也没用,未解决验证码位数:位数可改核心代码) public $layout = false;//隐藏导航 public function actions(){ return [ // ...

  7. 阿里云服务器创建swap分区

    阿里云服务器使用了4核8G内存配置,但最近由于jenkins构建时执行gradle打包安卓应用,导致即时的内存严重不足,线上应用长时间无法访问. 执行free命令才发现,swap分区一直是没有创建的. ...

  8. 图的邻接矩阵存储实现,C++描述

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  9. 二叉树实现,C++语言描述

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  10. (C/C++学习笔记) 五. 常变量(只读变量)和宏

    五. 常变量(只读变量)和宏 ● 常变量 常变量 #include <iostream.h>                    //预处理文件 int main() { const d ...