freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课
FreeBuf+小程序

FreeBuf+小程序

官方公众号企业安全新浪微博

国内领先的互联网安全新媒体,同时也是爱好者们交流与分享安全技术的社区

关于一个macOS 10.12.2到macOS 10.12.6内核崩溃问题的思索
2017-07-28 15:00:16

*本文原创作者:GentleKnife,本文属于FreeBuf原创奖励计划,禁止转载

首先申明的是这不是个利用,这个问题只能导致macOS 10.12.2~macOS 10.12.6内核崩溃。其次我曾在macOS 10.12.6发布的当天凌晨给苹果安全部门去信,这几天交流下来,苹果安全部门的口吻是这不是个安全问题,所以秉承着这仅仅是个BUG的原则,我们可以自由讨论这个BUG是怎么产生的以及影响如何。最后本人新人一枚,研究问题的能力有限,如果有大牛觉得这个问题能造成更深层次的问题,那么权当我抛砖引玉,感激不尽。本人也是第一次投稿,如有写错的地方请大家多多包涵。

我们先来看macOS 10.12.4(当前在opensource.apple.com公布的macOS的最新源码版本)IOPCIFamily的源代码,浏览至IOPCIBridge.c我们可以看到一个一直躺在那里的BUG:

关于一个macOS 10.12.2 到 macOS 10.12.6 内核崩溃问题的思索

当我们new一个IOPCIBridge且指定的type是kIOPCIDiagnosticsClientType时,实际new的是IOPCIDiagnosticsClient,我们再看这个实例在申请到内存后调用的initWithTask方法:

关于一个macOS 10.12.2 到 macOS 10.12.6 内核崩溃问题的思索

kIOClientPrivilegeAdministrator == root,所以我们用用户权限新建一个IOPCIBridge的client时,内核在调用initWithTask方法会返回false,即使我们使用root权限,PE_i_can_has_debugger判断失败也会返回false。

到这里其实都没有问题,问题出在由于先调用OSTypeAlloc申请了内存,并用uc指针指向这片内存,所以即使initWithTask返回false后,uc指针也是非空的,代码逻辑会去调用inPlane(gIOServicePlane)。这个函数继承自父类IORegistryEntry,我们来看源码:

关于一个macOS 10.12.2 到 macOS 10.12.6 内核崩溃问题的思索

据崩溃信息指向的就是这个函数,先贴出ida的结果:

关于一个macOS 10.12.2 到 macOS 10.12.6 内核崩溃问题的思索

实际崩溃在0xFFFFFF801A489D65       mov     rax, [rdi]这一行,rdi==0x0000000000000000。瞧,我们发现是空指针的解引用导致了内核的崩溃。

那么是getParentSetReference引发的崩溃?……从ida结果来看,不知道是不是编译器做了什么奇怪的优化,0xFFFFFF801A489D6C这一行怎么看都不像是在调用IORegistryEntry::getParentSetReference这个函数,倒像是编译器把这个函数“inline”掉了。如果照此推断,我们继续看该函数的源码:

关于一个macOS 10.12.2 到 macOS 10.12.6 内核崩溃问题的思索

注意registryTable()这个函数,其实是个宏,我们来看定义:

关于一个macOS 10.12.2 到 macOS 10.12.6 内核崩溃问题的思索

我们再看IORegistryEntry类中对fRegistryTable的定义:

关于一个macOS 10.12.2 到 macOS 10.12.6 内核崩溃问题的思索

我们注意到这其实是IORegistryEntry类中的一个成员指针,而此变量只有在IORegistryEntry::init被调用后才会非空。

到此为止,如果倒推这个问题,那么所有的一切都能恍然大悟。还记得最一开始提到的IOPCIDiagnosticsClient::initWithTask这个函数。如果这个函数最终返回true,那么通过层层函数调用,IORegistryEntry::init将被调用,也就不会触发空指针解引用的问题。

那么接下来揣摩一下coder的思维逻辑。macOS 10.12.2以下并没有触发内核崩溃,我们浏览macOS 10.12.1的源码:

关于一个macOS 10.12.2 到 macOS 10.12.6 内核崩溃问题的思索

由于先做了判断,然后再去申请内存,所以uc == null的话就不会去调用inPlane,也就不会触发内核崩溃。macOS 10.12.2及以后coder可能想要优化代码,把判断挪进initWithTask中去了,却忘了要适当的修改代码。

最后说说空指针解引用能不能利用。苹果安全部门给我的答案是NO。OS X 10.10,10.11时代答案也许是YES,因为32位程序是允许map第一个page页的,虽然macOS 10.12也能map,但是测试下来似乎苹果已经加固了这部分缺陷。

如果想测试这个崩溃问题十分简单,苹果自己的源代码就可以测试(汗……苹果为什么不自己测试?),具体路径在IOPCIFamily/tools/pcidump.c。以彼之矛,攻彼之盾,祝大家崩溃day开心!

*本文原创作者:GentleKnife,本文属于FreeBuf原创奖励计划,禁止转载

本文作者:, 属于FreeBuf原创奖励计划,未经许可禁止转载

# 内核 # macOS
被以下专栏收录,发现更多精彩内容
+ 收入我的专栏
评论 按时间排序

登录/注册后在FreeBuf发布内容哦

相关推荐
  • 0 文章数
  • 0 评论数
  • 0 关注者
登录 / 注册后在FreeBuf发布内容哦