首页 > 其他分享 >Address Sanitizer

Address Sanitizer

时间:2024-07-08 09:41:24浏览次数:10  
标签:字节 映射 Sanitizer 内存 Address shadow 红区

Address Sanitizer

Introduction

Address Sanitizer是一款内存检测器,它可以检测在堆栈,全局变量等地方的溢出。后来被整合到了GCC等编译器中,Address Sanitizer由两部分组成:一个Instrumentation模块和一个运行时库。Instrumentation模块修改代码来检查每个内存访问的影子状态,并在堆栈和全局对象周围创建有毒的红色区域,以检测溢出和下溢。运行时库替换malloc、free和相关函数,在分配的堆区域周围创建有毒的红区,延迟释放堆区域的重用,并进行错误报告。Address Sanitizer使用影子内存来记录应用程序内存的每个字节是否可以安全访问,并使用仪器检查每个应用程序负载或存储上的影子内存。


Shadow Memory

​ malloc函数返回以8字节为单位,一般前k个字节是可以寻址的,后8-k个字节不可以,那么就有9种状态。规则具体为:0表示所有都可以寻址,K(1≤K≤7)表示前K字节是可寻址的,负值表示整个都不可以寻址,不同的负值来区分不同类型的不可寻址内存(堆红区、堆栈红区、全局红区、释放内存)。那么就可以用1个字节来存储,这种8:1的放缩形式导致影子内存的空间减少。

​ 地址转化时,使用偏移量来进行计算,可以理解为映射规则为(Addr>>Scale)+Offset。offset的设置也有相应的要求,选取的 Offset 应该满足如下约束:影子内存的地址段, 也就是 Offset 到 (Offset+Max)/8 的地址段,不能被应用程序用到。

​ 如下图所示,因为每一个内存memory都会进行一次shadow memory的映射,所以把应用程序的内存给映射为shadow,把shadow部分给映射为bad区域,bad区域就是一个不可访问的区域。

​ 映射规则可以细分为直接映射和间接映射,直接映射的代表性的例子是 TaintTrace 和 LIFT。TaintTrace 按照 1:1 映射。缺点就是无法处理内存需求特别大的被检测程序 ,如果被检测程序使用了一半以上的地址空间,那就没有足够的地址空间来容纳影子内存了。相比来说,LIFT 使用 8:1 的比例设置影子内存。间接映射的代表是 valgrind 和 Dr.Memory。他们设置多个影子内存段,然后配合查表法来完成映射。


Instrumentation

​ 当检测一个8字节的内存访问时,Address Sanitizer计算相应影子字节的地址,加载该字节,并检查它是否为零:

ShadowAddr = (Addr >> 3) + Offset;	// 取地址中的字节
if (*ShadowAddr != 0)	ReportAndCrash(Addr);	// 如果不为0那么就报告

​ 当检测1、2或4字节访问时,检测稍微复杂一些:如果阴影值为正(即,8字节字中只有前k个字节是可寻址的),我们需要将地址的最后3位与k进行比较:

ShadowAddr = (Addr >> 3) + Offset;	// 取地址中的字节
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k))	ReportAndCrash(Addr);

ReportAndCrash的实现方式为简单的函数调用或者硬件异常指令。

​ 本技术将Address Sanitizer Instrumentation通道放置在LLVM优化管道的最末端。只记录那些在LLVM优化器执行的所有标量和循环优化中幸存下来的内存访问。例如,对由LLVM优化掉的本地堆栈对象的内存访问将不会被检测。同时,我们不需要测量由LLVM代码生成器生成的内存访问(例如,寄存器溢出)。


Run-time Library

​ 允许库中malloc和free函数也被专门函数取代,将malloc申请的堆块附近加入红区,可以认为是无法寻址访问被poisoned的区域。如果想防住Buffer Overflow漏洞,只需要在每块内存区域右端(或两端,能防overflow和underflow)加一块区域(RedZone),使RedZone的区域的影子内存(Shadow Memory)设置为不可写即可。

​ 对于全局变量,红区是在编译时创建的,红区地址在应用程序启动时传递给运行时库。运行时库函数毒害红区并记录地址,以便进一步报告错误。对于堆栈对象,红区是在运行时创建和毒害的。举个例子:

void foo() {
	char a[10];
	<function body>
}

​ 在函数调用的时候会进行创建红区:

void foo() {
	char rz1[32];
	char arr[10];
	char rz2[32-10+32];
	unsigned *shadow =(unsigned*)(((long)rz1>>8)+Offset);
    // poison the redzones around arr.
    shadow[0] = 0xffffffff; // rz1
    shadow[1] = 0xffff0200; // arr and rz2
    shadow[2] = 0xffffffff; // rz2
    <function body>
    // un-poison all.
    shadow[0] = shadow[1] = shadow[2] = 0;
}

Example

如下图所示,我们拿Ubuntu22.04作为例子来演示Heap上的溢出,在编译的时候加入选项g++ -fsanitize=address -g main.cpp

#include <iostream>
#include <cstring>
char* memoryOverflowExample()
{
    char* ret = new char;
    strcpy(ret, "Hello World\r\n");
    return ret;
}
int main()
{
    char* ret = memoryOverflowExample();
    std::cout << ret << std::endl;
    delete ret;
}

当运行的时候,首先他会现实调用的函数栈,然后会显示shadow memory上的状态,中括号为申请空间的映射,其中的定义为上述定义所示,然后旁边被红区包围,因为它是堆上的申请,所以旁边显示为Heap left redzone。

它所能检测出来的错误:


Reference article

AddressSanitizer: A Fast Address Sanity Checker | USENIX

https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm

标签:字节,映射,Sanitizer,内存,Address,shadow,红区
From: https://www.cnblogs.com/Dydong/p/18289319

相关文章

  • CF292C Beautiful IP Addresses 题解(两种写法)
    题意一个IP地址是一个32位的2进制整数,分成四组8位的2进制整数(没有前导0)。比如说,0.255.1.123 是一个正确的IP地址,而0.256.1.123 和 0.255.1.01 不是正确的。定义一个合法的回文IP地址为BeautifulIPAddress(回文地址就是去掉“.”后是个回文字符串的地......
  • 微信SDK与Unity的Addressables发生引用冲突的解决办法
    当我使用Unity的Addressables和微信的minigame-SDK时,会发生一个CS0433的报错,如下图所示: 关于CS0433错误,微软的官方文档中是这么描述的: 因此,根据报错信息,我揣测是Unity的Compat与mscorlib发生了重复,所以将mscorlib.dll文件全部删除了,但是问题没有得到解决,后面在一个大佬的帮......
  • 【Addressable】Catalog文件大小优化
    在Unity中使用Addressables系统时,AddressableCatalog文件的大小可能会影响加载时间和性能。以下是一些降低AddressableCatalog文件大小的方法:1.减少冗余的地址标签确保每个Addressable资产只使用必要的标签。避免给每个资产附加过多的标签,因为标签会增加Catalog文......
  • 【Java】InetAddress.isReachable()失效的底层原因探究
    文章目录背景现象问题原因总结背景在某些场景下,我们可能需要在Java中判断到某个主机的网络是否连通,比如我们的系统中可能有业务需要录入一些主机信息,此时为了更好的用户体验,我们可能会在前端页面上提供一个拨测按钮,让用户可以在输入主机地址之后进行连通性检验,来判......
  • D-Bus——DBUS_SESSION_BUS_ADDRESS 环境变量为空
            DBUS_SESSION_BUS_ADDRESS环境变量通常在用户会话环境中定义,用于指示会话总线的地址。在root用户环境下,这个环境变量可能为空,原因如下:原因分析会话总线与用户会话相关:        会话总线(sessionbus)是与特定用户会话相关的总线,每个用户登录后都会......
  • Cannot assign requested address 问题排查
    Cannotassignrequestedaddress问题排查背景工单服务调用了我提供的自动化接口,但是显示调用失败,失败原因:Cannotassignrequestedaddress.排查过程根据提示猜测是端口用尽.登录机器查看:>>>netstat-nap|grepTIME_WAIT|awk'{print$5}'|sort|uniq-c|......
  • Notes: Understanding the linux kernel Chapter 9 Process Address Space
    ProcessAddressSpaceWhenaUserModeprocessasksfordynamicmemory,itdoesn’tgetadditionalpageframes;instead,itgetstherighttouseanewrangeoflinearaddresses,whichbecomepartofitsaddressspace.Thisintervaliscalleda“memoryre......
  • ARP(Address Resolution Protocol)地址解析协议详解
    ARP地址解析解析ARP地址解析协议提供了一种在IPv4地址和硬件地址之间的动态映射。动态是因为它会自动执行和随时间变化,不需要系统管理员重新配置。若一台主机改变了网络接口卡,从而改变了它的硬件地址,ARP可以在一定延时后继续正常运作。举个例子:当我们使用Internet服务......
  • objcopy change-address参数
    在`objcopy`这个GNUBinutils工具中,`--change-address`(或简写为`-R`)参数用于修改输出文件中各个段的起始地址。这在处理二进制镜像(例如U-BootSPL,即SecondaryProgramLoader)时特别有用,因为你可能需要将这些镜像加载到特定的内存地址。具体来说,`--change-address=ADDRESS`参数......
  • Addressrec:地址解析库
    在我们的日常工作中,特别是数据分析、地理信息系统(GIS)开发,或者在线零售等行业中,经常会遇到处理包含地址信息的文本数据这个棘手的任务。面对大量规格不统一,格式不一致的非结构化地址数据,想要从中快速地提取分级地址、联系人、电话等,简直就是不可能完成的任务。即使费九牛二虎......