0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一文解析AddressSanitizer算法及源码

Linux阅码场 来源:网络整理 作者:工程师陈翠 2018-07-28 11:41 次阅读

AddressSanitizer简介

AddressSanitizer是Google用于检测内存各种buffer overflow(Heap buffer overflow, Stack buffer overflow, Global buffer overflow)的一个非常有用的工具。该工具是一个LLVM的Pass,现已集成至llvm中,要是用它可以通过-fsanitizer=address选项使用它。AddressSanitizer的源码位于/lib/Transforms/Instrumentation/AddressSanitizer.cpp中,Runtime-library的源码在llvm的另一个项目compiler-rt的/lib/asan文件夹中。

AddressSanitizer算法

具体的算法可以参考WIKI(https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm),在此对AddressSanitizer算法做一个简短的介绍。AddressSanitizer主要包括两部分:插桩(Instrumentation)和动态运行库(Run-time library)。插桩主要是针对在llvm编译器级别对访问内存的操作(store,load,alloca等),将它们进行处理。动态运行库主要提供一些运行时的复杂的功能(比如poison/unpoison shadow memory)以及将malloc,free等系统调用函数hook住。其实该算法的思路很简单,如果想防住Buffer Overflow漏洞,只需要在每块内存区域右端(或两端,能防overflow和underflow)加一块区域(RedZone),使RedZone的区域的影子内存(Shadow Memory)设置为不可写即可。具体的示意图如下图所示。

一文解析AddressSanitizer算法及源码

内存映射

AddressSanitizer保护的主要原理是对程序中的虚拟内存提供粗粒度的影子内存(每8个字节的内存对应一个字节的影子内存),为了减少overhead,就采用了直接内存映射策略,所采用的具体策略如下:Shadow=(Mem >> 3) + offset。每8个字节的内存对应一个字节的影子内存,影子内存中每个字节存取一个数字k,如果k=0,则表示该影子内存对应的8个字节的内存都能访问,如果0

一文解析AddressSanitizer算法及源码

图1: 虚拟地址映射图

一文解析AddressSanitizer算法及源码

插桩

为了防止buffer overflow,需要将原来分配的内存两边分配额外的内存Redzone,并将这两边的内存加锁,设为不能访问状态,这样可以有效的防止buffer overflow(但不能杜绝buffer overflow)。一下是在栈中插桩的一个例子。

未插桩的代码:

一文解析AddressSanitizer算法及源码

插桩后的代码:

一文解析AddressSanitizer算法及源码

动态运行库

在动态运行库中将malloc/free函数进行了替换。在malloc函数中额外的分配了Redzone区域的内存,将与Redzone区域对应的影子内存加锁,主要的内存区域对应的影子内存不加锁。

free函数将所有分配的内存区域加锁,并放到了隔离区域的队列中(保证在一定的时间内不会再被malloc函数分配)。

AddressSanitizer源码分析

AddressSanitizer主要有三种层面的变量:Stack Variable(局部变量),Global Variable, Heap Variable。由于每种变量的生命周期(life time)不同,所以对不同种类的变量处理也是不同的。下面分别从Global Variable,Stack Variable,Heap Variable三个层次来分析AddressSanitizer源码的逻辑结构。

Global Variable

Global Variable存放在程序的数据段。在该算法的实现过程中,处理GlobalVariale的是AddressSanitizerModule类,该类继承自llvm的ModulePass,所以我们先看一下AddressSanitizerModule类的runOnModule(Module &M)方法的处理过程,该过程首先进行一些初始化,然后我们可以看到对Global的插桩方法InstrumentGlobals()方法。

一文解析AddressSanitizer算法及源码

图2: RunOnModule

在InstrumentGlobals()方法中,主要是分成两步:首先,重新声明一个GlobalVariable,这个GlobalVariable包含以前的GlobalVariable和一个RedZone;然后,调用runtime-library将新声明的这个GlobalVariable的RedZone区域加锁。我们先来看第一步的具体实现,如图3所示。

一文解析AddressSanitizer算法及源码

图3: 生成包含RedZone的新的GlobalVariable

下面,我们首先看一下一个Struct结构,该结构记录GlobalVariable存储的首地址,数据的大小,Redzone的大小,Module的名字等信息,便于在Runtime-library中使用。该结构在AddressSanitizerModule和runtime-library中都有相应的定义:

一文解析AddressSanitizer算法及源码

一文解析AddressSanitizer算法及源码

然后我们可以看到对GlobalVariable进行插桩来实现RedZone的Poison和整个GlobalVariable的Poison操作。

一文解析AddressSanitizer算法及源码

一文解析AddressSanitizer算法及源码

具体的Poison RedZone和Poison GlobalVariable的实现在Runtime-library中:

一文解析AddressSanitizer算法及源码

一文解析AddressSanitizer算法及源码

Stack Variable

Stack Variable保存在栈区,在栈中的数据我们需要控制好变量的声明周期(lifetime),当调用一个函数时,会开辟一个栈,栈中的数据会有相应的redzone和shadow memory,并将redzone的shadow memory Poison,当函数结束(正常返回,异常),栈被销毁,需要将数据和redzone清空,其相应的shadow memory也要UnPoison掉。

对于Stack Variable,AddressSanitizer算法中实现了AddressSanitizer类,该类是继承了llvm的FunctionPass,该Pass能够处理每一个函数,在处理每个函数的时候,处理每一个load,store等能够访问内存的指令,在这些指令执行前进行插桩,看其访问的内存是不是被poison。

下面我们主要看一下AddressSanitizer::runOnFunction(Module &M)函数中主要的插桩过程。

一文解析AddressSanitizer算法及源码

在每次访问内存时,都会查看影子内存的值,看其是否是0,如果是0则表示都能访问具体的插桩在instrumentMop函数中,

一文解析AddressSanitizer算法及源码

其中具体的处理过程在instrumentAddress函数中:

一文解析AddressSanitizer算法及源码

Heap Variable

Heap Variable保存在堆区,其分配的函数是malloc函数,该部分的主要代码在runtime-library中,该库中主要是先将malloc的库函数hook住,然后自己定义malloc函数,定义分配策略。

一文解析AddressSanitizer算法及源码

具体的分配策略定义在compiler-rt/lib/asan/asan-allocator.cc文件中,感兴趣可以看一下。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Google
    +关注

    关注

    5

    文章

    1758

    浏览量

    57418

原文标题:AddressSanitizer算法及源码解析

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    【安全算法之DES】DES算法的C语言源码实现

    【安全算法之DES】DES算法(支持ECB/CBC模式)的C语言源码实现
    的头像 发表于 09-20 08:58 4739次阅读
    【安全<b class='flag-5'>算法</b>之DES】DES<b class='flag-5'>算法</b>的C语言<b class='flag-5'>源码</b>实现

    Spark运行架构与源码解析

    Spark 源码解析DAGScheduler中的DAG划分与提交
    发表于 04-24 06:32

    PID算法解析,绝对实用

    PID算法解析,绝对实用
    发表于 01-21 07:40

    解析Memory安全和硬件Memory Tagging技术(2)

    现有的工具和实践编程实践和测试工具减少了内存bug的可能性。测试驱动的开发流程和如AddressSanitizer或Valgrind的动态测试工具起可以帮助避免内存bug. Fuzzing
    发表于 08-18 11:24

    PID控制算法C语言源码

    PID控制算法C语言源码包括程序源码以及数据仿真结果。
    发表于 12-02 15:33 27次下载

    源码-易语言常用算法

    易语言是门以中文作为程序代码编程语言学习例程:易语言-源码-易语言常用算法
    发表于 06-06 17:43 4次下载

    178个与算法有关的C语言源码

    178个与算法有关的C语言源码源码很好,无论对初学者还是老程序员都有帮助。下载后好好学习吧。
    发表于 08-18 18:00 11次下载

    Uboot中start.S源码的指令级的详尽解析

    Uboot中start.S源码的指令级的详尽解析
    发表于 10-30 08:47 28次下载
    Uboot中start.S<b class='flag-5'>源码</b>的指令级的详尽<b class='flag-5'>解析</b>

    基于java的负载均衡算法解析源码分享

    负载均衡的算法实际上就是解决跨系统调用的时候,在考虑后端机器承载情况的前提下,保证请求分配的平衡和合理。下面是基于java的负载均衡算法解析源码,以供参考。
    发表于 01-01 19:29 2209次阅读

    解析PLC的应用

    解析PLC的应用,具体的跟随小编起来了解下。
    的头像 发表于 07-19 11:21 5225次阅读
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>解析</b>PLC的应用

    基于EAIDK的人脸算法应用-源码解读(2)

    期介绍了基于EAIDK的人脸算法应用,本期从应用角度,解读下该案例源码。本期案例源码解读,主要从
    的头像 发表于 12-10 21:14 856次阅读

    Navigation源码解析

    Navigation源码解析 谷歌推出Navigation主要是为了统应用内页面跳转行为。本文主要是根据Navigation版本为2.1.0 的源码进行讲解
    的头像 发表于 06-15 16:38 1731次阅读

    简述hex文件解析源码

    简述hex文件解析源码
    发表于 09-12 09:20 8次下载

    云海计费系统v4.1 视频解析解析收费接口专用 短视频解析解析收费接口专用 影视视频电影解析计费平台源码程序

    介绍:云海计费系统v4.1 视频解析 短视频解析 影视视频电影解析计费平台源码程序云海解析计费系统是
    发表于 01-11 16:02 13次下载
    云海计费系统v4.1 视频<b class='flag-5'>解析</b><b class='flag-5'>解析</b>收费接口专用 短视频<b class='flag-5'>解析</b><b class='flag-5'>解析</b>收费接口专用 影视视频电影<b class='flag-5'>解析</b>计费平台<b class='flag-5'>源码</b>程序

    Java算法大全源码包开源源码

    Java算法大全源码包开源源码
    发表于 06-07 14:58 1次下载