首页
社区
课程
招聘
[原创]cve-2016-3842分析
发表于: 2017-6-2 11:43 5064

[原创]cve-2016-3842分析

2017-6-2 11:43
5064

static const struct {

unsigned int cmd;

kgsl_ioctl_func_t func;

unsigned int flags;

} kgsl_ioctl_funcs[] = {

KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,

kgsl_ioctl_device_getproperty,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,

kgsl_ioctl_device_waittimestamp,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,

kgsl_ioctl_device_waittimestamp_ctxtid,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,

kgsl_ioctl_rb_issueibcmds, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS,

kgsl_ioctl_submit_commands, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,

kgsl_ioctl_cmdstream_readtimestamp,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID,

kgsl_ioctl_cmdstream_readtimestamp_ctxtid,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,

kgsl_ioctl_cmdstream_freememontimestamp,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,

kgsl_ioctl_cmdstream_freememontimestamp_ctxtid,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,

kgsl_ioctl_drawctxt_create,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,

kgsl_ioctl_drawctxt_destroy,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_MAP_USER_MEM,

kgsl_ioctl_map_user_mem, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FROM_PMEM,

kgsl_ioctl_map_user_mem, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FREE,

kgsl_ioctl_sharedmem_free, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE,

kgsl_ioctl_sharedmem_flush_cache, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC,

kgsl_ioctl_gpumem_alloc, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_SYNCMEM,

kgsl_ioctl_cff_syncmem, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT,

kgsl_ioctl_cff_user_event, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,

kgsl_ioctl_timestamp_event,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,

kgsl_ioctl_device_setproperty,

KGSL_IOCTL_LOCK),

KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,

kgsl_ioctl_gpumem_alloc_id, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,

kgsl_ioctl_gpumem_free_id, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO,

kgsl_ioctl_gpumem_get_info, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,

kgsl_ioctl_gpumem_sync_cache, 0),

KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK,

kgsl_ioctl_gpumem_sync_cache_bulk, 0),

};




1.首先,我们来看漏洞的形成原因。

$1

 漏洞产生代码 和 利用方案主要都在 都在kgsl_ioctl_gpumem_alloc_id函数 里面


  首先,我们先看看漏洞产生的函数.

  result = kgsl_mem_entry_attach_process(entry, dev_priv);   // 这个函数产生了漏洞

 

现在我们来看看这里面都有些什么内容。

static int

kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,

  struct kgsl_device_private *dev_priv)

{

...  这里添加到了idr中

id = idr_alloc(&process->mem_idr, entry, 1, 0, GFP_NOWAIT);

...

在调用 kgsl_mmu_map 之前  把entry释放掉 造成UAF?

ret = kgsl_mmu_map(pagetable, &entry->memdesc);

...

}

上面是我打印出来的几个和漏洞相关的重要函数

首先是第一个 漏洞参数主要在这个函数内。 首先来看看 idr_alloc  

这个函数 主要是给管理对象,会给对象分配一个编号,然后我们可以再次通过这个编号找到要管理的对象。

                        重要的是这个编号是按照顺序排序的。第一个对方存放进去的时候 返回的 ID 将会是1  这个很重要。销毁对象的时候我们将会用到

我们再来看看销毁对象是怎么做的。

销毁对象的方式有很多,但是其中有一个  IOCTL_KGSL_GPUMEM_FREE_ID 他是根据idr 编号找到对象,然后进行销毁。

释放内存 造成漏洞形成

ioctl(fd,IOCTL_KGSL_GPUMEM_FREE_ID, &arg_free);

通过调用路径我们找到 最终会调用下面的这个函数来销毁对象 ,我们再来具体分析

static long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,

unsigned int cmd, void *data)

{

struct kgsl_gpumem_free_id *param = data;

struct kgsl_process_private *private = dev_priv->process_priv;

struct kgsl_mem_entry *entry = NULL;

entry = kgsl_sharedmem_find_id(private, param->id);

         ...

/*

* First kgsl_mem_entry_put is for the reference that we took in

* this function when calling kgsl_sharedmem_find_id, second one is

* to free the memory since this is a free ioctl

*/

kgsl_mem_entry_put(entry);

return 0;

}

entry = kgsl_sharedmem_find_id(private, param->id);注意这个函数

                        他是根据ID 来获取到对象的,而我们已经知道idr_alloc的编号是按顺序发放的

                        struct kgsl_gpumem_free_id *param = data; 中的data 使我们从用户空间传入的 

                        那么就是说 param->id 我们可以直接赋值 1的话,他会返回我们kgsl_mem_entry_attach_process函数中

                        管理的entry对象 最后销毁entry对象 

                        

这个调用过程,单线程跑的话。是不会有问题的。

但是如果我们假设用双线程跑到某种特殊的情况下又会是怎么样呢?


                        现在我们来假设一下情况。

首先第一个线程

kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,

  struct kgsl_device_private *dev_priv)

{

...  

id = idr_alloc(&process->mem_idr, entry, 1, 0, GFP_NOWAIT);

线程1:跑到这里,然后创建了ID,保存了对象。 ID ret 1

                                这时候 cpu切换到线程2,开始执行线程2的代码

    ...

}

第二个线程

static long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,

unsigned int cmd, void *data)

{

entry = kgsl_sharedmem_find_id(private, param->id);

kgsl_mem_entry_put(entry);

线程2:执行完这个函数。根据ID 找到了 entry 对象,最后然后释放了entry

}

然后cpu切换到线程1再继续往下执行的话。我们发现 线程1所用的 entry 对象已经被线程2释放掉了。

这样漏洞就被触发了.


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 416
活跃值: (117)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
2
为了提供漏洞成功率,可以将线程1  和  线程2  和cpu进行绑定,再设置线程优先级,这样能提高成功率
2017-6-2 11:47
0
雪    币: 1037
活跃值: (1780)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
标识看不懂啊
2017-6-2 16:55
0
游客
登录 | 注册 方可回帖
返回
//