CN117785540A - 内存错误检测方法、装置、设备及介质 - Google Patents

内存错误检测方法、装置、设备及介质 Download PDF

Info

Publication number
CN117785540A
CN117785540A CN202410006515.6A CN202410006515A CN117785540A CN 117785540 A CN117785540 A CN 117785540A CN 202410006515 A CN202410006515 A CN 202410006515A CN 117785540 A CN117785540 A CN 117785540A
Authority
CN
China
Prior art keywords
memory
program
shadow
information
analysis
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
CN202410006515.6A
Other languages
English (en)
Inventor
王晓磊
张斌
冯超
李瑞林
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
National University of Defense Technology
Original Assignee
National University of Defense Technology
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by National University of Defense Technology filed Critical National University of Defense Technology
Priority to CN202410006515.6A priority Critical patent/CN117785540A/zh
Publication of CN117785540A publication Critical patent/CN117785540A/zh
Pending legal-status Critical Current

Links

Landscapes

  • Debugging And Monitoring (AREA)

Abstract

本发明涉及计算机技术领域,公开了一种内存错误检测方法、装置、设备及介质,该方法包括:提取源代码的基础程序信息;对基础程序信息中函数、变量、内存对象的高层语义信息进行解析;将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间;根据语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询多重影子内存中存储的元数据并插入安全检查代码;运行代码插桩后的程序,对内存错误漏洞进行检测。这样利用多重影子内存中存储的元数据结合插入的安全检查代码,能够实现对特定复杂、多种类型内存错误漏洞的精准检测,降低内存错误的漏报率。

Description

内存错误检测方法、装置、设备及介质
技术领域
本发明涉及计算机技术领域,特别是涉及一种内存错误检测方法、装置、设备及介质。
背景技术
自操作系统诞生以来,编写内存安全的代码一直是一个难题。内存错误是软件中常见的问题,尤其是采用不安全程序语言开发的内核等底层软件。内存错误会导致应用程序崩溃、数据泄露等安全漏洞,因此在大规模和复杂的软件开发、测试过程中,检测和修复内存漏洞变得至关重要,相应的,对于内存漏洞检测工具的需求也变得非常迫切。
以当前业界普遍使用的内存错误检测器(Address Sanitizer,ASAN)为例,它常常被用于在模糊测试中,检测C/C++程序中存在的内存漏洞,例如缓冲区溢出或对悬空指针的非法访问等。C/C++项目通常会使用ASAN来保证产品质量,尤其是大型软件开发项目中更为需要。但是ASAN在设计上并非完备,很多情况下,它并不能有效地发现程序中包含的某些内存错误,例如未初始化变量使用、空指针解引用等,易产生漏报。
因此,提供一种更精确的内存错误检测方法是本领域人员亟需解决的技术问题。
发明内容
本发明的目的是提供一种内存错误检测方法、装置、设备及介质,可以实现对特定复杂、多种类型内存错误漏洞的精准检测,降低内存错误的漏报率。
为了解决上述技术问题,本发明提供一种内存错误检测方法,所述方法包括:
提取源代码的基础程序信息;
对所述基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息;
将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间;
根据所述语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询所述多重影子内存中存储的元数据并插入安全检查代码;
运行代码插桩后的程序,对内存错误漏洞进行检测。
第一方面,在本发明实施例提供的上述内存错误检测方法中,所述提取源代码的基础程序信息,包括:
接收所述源代码,利用LLVM编译器构建程序的抽象语法树;
利用所述LLVM编译器编译所述源代码,并将编译后的所述源代码转换为LLVM IR指令;
对所述LLVM IR指令进行控制流分析和静态值流分析,分别获取控制流信息和构造程序的值流图,以提取所述源代码的基础程序信息。
另一方面,在本发明实施例提供的上述内存错误检测方法中,所述对所述基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息,包括:
根据获取的所述控制流信息,对与函数调用相关的所述LLVM IR指令进行分析,获得调用点的直接调用关系、间接调用关系、目标函数名称、参数类型及数量、返回值及返回值类型;
在变量生命周期分析过程中,创建局部变量的AllocaInst进行插桩分析,获得变量的创建点;
借助所述抽象语法树对VarDecl节点所属的域进行分析,并在域结束时插入指令,以标记变量的销毁点;
在内存对象生命周期分析过程中,开始于内存分配的调用点,结束于内存释放的调用点;
将变量和内存对象生命周期的分析结果保存至运行时库的全局数组中,并随着程序运行进行动态更新;
对内存对象进行边界分析,得到不同类型对象所占的内存范围;
对变量进行指向分析,得到设定指针变量指向的内存对象集合。
另一方面,在本发明实施例提供的上述内存错误检测方法中,所述对变量进行指向分析,得到设定指针变量指向的内存对象集合,包括:
在构造的所述值流图上定位设定指针变量所在的节点,迭代分析所述节点的前驱节点,直至找到以AllocaInst创建的临时变量、静态声明的全局变量和堆上分配的临时变量,结合指针别名分析,筛选出对应的内存对象。
另一方面,在本发明实施例提供的上述内存错误检测方法中,所述将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间,包括:
将原始ASAN中的应用内存空间划分为所述主内存和新影子内存;所述新影子内存和所述原始ASAN中的影子内存组成所述多重影子内存;所述新影子内存检测的内存错误漏洞类型与所述原始ASAN中的影子内存检测的内存错误漏洞类型不同;
在将主内存地址空间映射到所述新影子内存地址空间的过程中,将主内存访问地址添加或减去相应的固定偏移。
另一方面,在本发明实施例提供的上述内存错误检测方法中,所述根据所述语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询所述多重影子内存中存储的元数据并插入安全检查,包括:
在所有内存对象生命周期开始的代码位置处,设置对应的所述新影子内存中的元数据;
识别出程序中所有的代码位置,并插入相应的代码,以传递源对象的元数据信息以及更新目标对象的元数据;
识别出程序中所有基于指针解引用的内存访问相关代码位置,并插入相应的内存来查询相应的元数据;
通过查询的元数据在程序中插入安全检查代码。
另一方面,在本发明实施例提供的上述内存错误检测方法中,所述运行代码插桩后的程序,对内存错误漏洞进行检测,包括:
使用相关命令行工具运行代码插桩后的程序;
执行相关程序路径,触发潜在的内存漏洞;
程序运行过程中,在执行到代码插桩插入的安全检查代码时,借助所述语义解析信息进行设定条件判断,以检测是否发生越界访问错误、未初始化内存使用漏洞、空指针解引用错误、释放后重用漏洞、二次释放漏洞。
为了解决上述技术问题,本发明还提供一种内存错误检测装置,所述装置包括:
程序分析模块,用于提取源代码的基础程序信息;
语义解析模块,用于对所述基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息;
内存划分模块,用于将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间;
代码插桩模块,用于根据所述语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询所述多重影子内存中存储的元数据并插入安全检查代码;
内存访问检测模块,用于运行代码插桩后的程序,对内存错误漏洞进行检测。
为了解决上述技术问题,本发明还提供一种内存错误检测设备,所述设备包括:
存储器,用于存储计算机程序;
处理器,用于执行所述计算机程序时实现上述的内存错误检测方法的步骤。
为了解决上述技术问题,本发明还提供一种计算机可读存储介质,所述计算机可读存储介质上存储有计算机程序,所述计算机程序被处理器执行时实现上述的内存错误检测方法的步骤。
从上述技术方案可以看出,本发明所提供的一种内存错误检测方法,该方法包括:提取源代码的基础程序信息;对基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息;将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间;根据语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询多重影子内存中存储的元数据并插入安全检查代码;运行代码插桩后的程序,对内存错误漏洞进行检测。
本发明的有益效果在于,本发明提供的上述内存错误检测方法,首先借助基础程序分析技术融合程序语义解析方式来提取程序基本信息,对程序语义进行深度解析,然后设计多重影子内存布局,再根据语义解析信息在程序中对应的操作位置上进行代码插桩,可以设置、更新和查询多重影子内存中存储的元数据并插入安全检查代码,这样利用多重影子内存中存储的元数据结合插入的安全检查代码,能够判定程序运行时是否有内存错误或漏洞,进而实现对程序内存访问行为的精准刻画和检查,可以同时检测多种类型的内存错误漏洞,还可以检测特定复杂的内存漏洞,降低内存错误的漏报率,大幅提升内存错误的检测精度。
此外,本发明还针对内存错误检测方法提供了相应的内存错误检测装置、内存错误检测设备及计算机可读存储介质,与上述提到的内存错误检测方法具有相同或相对应的技术特征,效果同上。
附图说明
为了更清楚地说明本发明实施例,下面将对实施例中所需要使用的附图做简单的介绍,显而易见地,下面描述中的附图仅仅是本发明的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。
图1为本发明实施例提供的内存错误检测方法的流程图;
图2为本发明实施例提供的内存错误检测方法的框架示意图;
图3为本发明实施例提供的多重影子内存布局划分示意图;
图4为本发明实施例提供的原始ASNS中主内存与影子内存之间映射关系示意图;
图5为本发明实施例提供的新影子内存中存储初始化状态的元数据的示意图;
图6为本发明实施例提供的新影子内存中存储指针标签的元数据的示意图;
图7为本发明的一实施例提供的内存错误检测装置的结构示意图;
图8为本发明另一实施例提供的内存错误检测设备的结构示意图。
具体实施方式
下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分实施例,而不是全部实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下,所获得的所有其他实施例,都属于本发明保护范围。
为了使本技术领域的人员更好地理解本发明方案,下面结合附图和具体实施方式对本发明作进一步的详细说明。图1为本发明实施例提供的一种内存错误检测方法的流程图,如图1所示,该方法包括:
S1、提取源代码的基础程序信息。
在实施中,如图2所示,步骤S1提取源代码的基础程序信息可以理解为基础程序分析。该步骤可以由位于整个系统最底层的程序分析模块来负责。
S2、对基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息。
需要说明的是,现有的内存错误检测方法大多只关注内存访问操作而忽略程序语义,无法准确刻画内存访问发生时的程序上下文信息、内存对象信息等,导致漏报。因此,本发明对程序语义进行了深度解析,为后续内存访问插桩和安全检查提供更为精准的相关信息。
在实施中,如图2所示,步骤S2对基础程序信息中函数、变量、内存对象的高层语义信息进行解析可以理解为程序语义解析。该步骤可以由语义解析模块来负责,具体可以在基础程序分析提供的信息基础上,对程序中函数/变量/内存对象的边界、生命周期、指向信息等高层语义信息进行解析,以满足上层漏洞检测引擎的语义需求。
在实际应用中,程序中的内存对象主要包括三类:第一类是全局变量(GlobalVariable),在所有函数外部定义的变量,既可以是某对象函数创建,也可以是在本程序任何地方创建。全局变量是可以被本程序所有对象或函数引用,它的作用域默认是整个程序,也就是所有的源文件。第二类是栈对象,由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。第三类是堆对象,一般由程序员分配释放,其大小由系统内存/虚拟内存上限决定,若程序员不释放,程序结束时可能由操作系统回收。它与数据结构中的堆不同,分配方式类似于链表。
S3、将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间。
需要说明的是,现有的影子内存布局一般只能服务于一种内存错误检测机制,无法服务于多个内存错误检测机制,因此,本发明设计了一个多重影子内存(Multi-ShadowMemory),多重影子内存指的就是创建多个影子内存,每个影子内存对应的内存错误漏洞类型是不同的,即多重影子内存能够存储多类元数据信息,可以同时服务于多个内存错误检测机制,提升检测精度。
在实际应用中,不同类型内存错误漏洞可以包括:释放后使用(Use after free,UAF)是堆上分配的空间释放之后被再次使用;堆缓冲区溢出(Heap buffer overflow)是内存访问的区域在堆上,且超过了分配的空间;栈缓冲区溢出(Stack buffer overflow)是内存访问的区域在栈上,且超过了分配给它的空间;全局缓冲区溢出(Global bufferoverflow)是内存访问的区域是全局变量,且超过了分配给它的空间;空指针解引用(Nullpointer dereference)是指程序试图解引用(访问指针指向的内存区域)一个为空(null)的指针,从而导致异常;重复释放(Double free)是将指向堆内存的指针释放两次;未初始化内存读(Uninitialized memory read)是指读取未赋值的已声明变量。
S4、根据语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询多重影子内存中存储的元数据并插入安全检查代码。
需要说明的是,代码插桩(Program Instrumentation)是动态分析过程中测试、定位问题的手段,通过在代码对应位置插入一些测量或是控制用的额外代码(“桩”),来打印、收集所需要的运行数据,或者监控程序运行时的行为。
本发明的代码插桩是指源代码插桩,是基于编译器的插桩,在对源文件进行完整的词法分析和语法分析的基础上进行的,这保证了对源文件的插桩能够达到很高的准确度和针对性。
较佳地,本发明的代码插桩可以利用LLVM编译器框架,先将源代码转换成LLVM IR形式,然后在LLVM IR中特定的位置插入函数调用或代码片段,这些插入的代码用于设置、更新和查询影子内存中存储的元数据,并插入安全检查来判定运行时是否有内存错误或漏洞。
S5、运行代码插桩后的程序,对内存错误漏洞进行检测。
本发明实施例提供的上述内存错误检测方法中,首先借助基础程序分析技术融合程序语义解析方式来提取程序基本信息,对程序语义进行深度解析,然后设计多重影子内存布局,再根据语义解析信息在程序中对应的操作位置上进行代码插桩,可以设置、更新和查询多重影子内存中存储的元数据并插入安全检查代码,这样访问多重影子内存中存储的元数据结合插入的安全检查代码,能够判定程序运行时是否有内存错误或漏洞,进而实现对程序内存访问行为的精准刻画和检查,可以同时检测多种类型的内存错误漏洞,还可以检测特定复杂的内存漏洞,降低内存错误的漏报率,大幅提升内存错误的检测精度。
进一步地,在具体实施时,在本发明实施例提供的上述内存错误检测方法中,步骤S1提取源代码的基础程序信息,具体可以包括:首先,接收源代码,利用LLVM编译器构建程序的抽象语法树;然后,利用LLVM编译器编译源代码,并将编译后的源代码转换为LLVM IR指令;之后,对LLVM IR指令进行控制流分析和静态值流分析,分别获取控制流信息和构造程序的值流图,以提取源代码的基础程序信息。
在实施中,程序分析模块主要可以包含抽象语法树分析、控制流分析和直流分析等内容。
其中,抽象语法树分析是以程序源代码为输入,借助LLVM编译器框架的Clang前端来构建程序的抽象语法树(AST),并提供友好的访问接口,便于上层的漏洞检测算法能够根据指定的规则进行AST节点的搜索。
控制流分析是先使用LLVM编译器框架的Clang前端编译源代码,并转换为LLVM IR指令,LLVM IR是LLVM中表示C/C++程序的一种特定中间指令表示形式,然后基于LLVM IR中间指令进行控制流分析,提取过程内的指令、基本块以及基本块之间的前驱后继关系、支配关系等,并提供友好访问接口,便于上层模块根据需求进行控制流信息的获取。
静态值流分析中的值流关系是进行程序变量间数据流传播关系分析的重要基础,值流图在传统数据流图的基础上,强化了程序变量(特别是指针和内存对象)之间的值传播关系,是程序优化、程序异常检测的重要基础。该部分同样基于LLVM IR表示,首先借助现有过程间静态值流分析框架SVF构造出程序的值流图,并提供友好的查询接口,便于上层的漏洞检测算法能够根据指定的规则进行变量间数据流关系的分析。
进一步地,在具体实施时,在本发明实施例提供的上述内存错误检测方法中,步骤S2对基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息,具体可以包括以下步骤:
步骤一、根据获取的控制流信息,对与函数调用相关的LLVM IR指令进行分析,获得调用点的直接调用关系、间接调用关系、目标函数名称、参数类型及数量、返回值及返回值类型。
在实施中,在底层控制流分析的基础上,对CallInst和InvokeInst等与函数调用相关的IR指令进行分析,获得调用点的直接/间接调用关系、目标函数名称、参数类型及数量、返回值及其类型等与函数调用紧密相关的信息。
步骤二、在变量生命周期分析过程中,创建局部变量的AllocaInst进行插桩分析,获得变量的创建点;借助抽象语法树对VarDecl节点所属的域进行分析,并在域结束时插入指令,以标记变量的销毁点。
在实施中,变量生命周期分析可以通过在编译时采用大于O0(一种编译优化等级)的优化获得lifetime.start和lifetime.end中间IR指令进行,但O0优化等级在漏洞挖掘中较为常用,因此这种方式并不适合。考虑到LLVM中非全局变量一般以局部变量的形式在过程内进行创建,因此本发明通过对LLVM中创建局部变量的AllocaInst进行插桩分析,从而获得变量的创建点。对于变量的销毁,则借助底层的抽象语法树(AST)分析引擎对VarDecl节点(AST中的一个节点)所属的域进行分析,并在域结束时插入指令从而标记变量的销毁点。
步骤三、在内存对象生命周期分析过程中,开始于内存分配的调用点,结束于内存释放的调用点;将变量和内存对象生命周期的分析结果保存至运行时库的全局数组中,并随着程序运行进行动态更新。
在实施中,内存对象生命周期分析较为方便,其生命开始于通过malloc/new等函数进行内存分配的调用点,结束于通过free/delete等函数进行内存释放的调用点。本发明在函数调用关系分析基础上,对malloc/new/free/delete等函数进行插桩,最终实现对内存对象的生命周期分析。变量和内存对象生命周期的分析结果存放在运行时库中建立的全局数组中,并随着程序运行进行动态更新。
步骤四、对内存对象进行边界分析,得到不同类型对象所占的内存范围。
在实施中,给定一个对象,对象边界分析旨在获取其所占的内存范围,包括起始地址startAddr和结束地址endAddr,此部分是在IR层完成。以数组类型对象为例,在对象边界分析过程中,首先提取出起始地址startAddr,紧接着获取该数组的元素个数n和元素类型t,根据元素类型t进行确定该元素类型的大小i,从而获取数组对象的大小为n*i,最终确定该对象的内存边界为[startAddr,startAddr+n*i]。对于结构体类等复合对象,本发明会获取对象中的每一个成员类型,类似的,根据成员类型分别计算大小,最终总和为该结构体类对象的大小。如果复合对象是嵌套的,上述分析过程可迭代进行。
步骤七、对变量进行指向分析,得到设定指针变量指向的内存对象集合。
在实施中,变量对象指向分析是指给定一个变量(例如C/C++中的指针变量),分析该指针变量可能指向的对象集合。变量指向对象分析是实现对结构体域内越界访问、跳跃越界访问等内存问题进行检测的关键。如下面的示例代码:
1:int buffer_A[10];
2:int buffer_B[20];
3:buffer_A[15]=66;
第3行代码经过Clang前端编译后,可得到“%1=getelementptr%buffer_A,0,15store i64 66,%1”这一LLVM IR中间指令,其中源代码buffer_A[15]=66经过编译后对应IR中间指令%1。由于漏洞检测的代码插桩是在IR层面进行的,为了应对跳跃越界访问这种情况,这里需要区分IR层面的变量%1到底是指向对象buffer_A还是buffer_B。
变量指向分析借助现有开源的静态数据流分析框架SVF,进行跨模块、跨过程的静态指针别名分析;然后在SVF已有的指针别名分析功能基础上,结合静态值流分析,实现变量指向分析。具体来讲,在给定一个变量后,首先在值流图上定位该变量所在的节点,然后迭代分析该节点的前驱节点,直至找到以AllocaInst(分配对象的指令)创建的临时变量、静态声明的全局变量和堆上的分配的临时变量,之后根据再调用指针别名分析功能,从中筛选出可能的内存对象。
进一步地,在具体实施时,在本发明实施例提供的上述内存错误检测方法中,步骤S3将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间,具体可以包括:将原始ASAN中的应用内存空间划分为主内存和新影子内存;新影子内存和原始ASAN中的影子内存组成多重影子内存;新影子内存检测的内存错误漏洞类型与原始ASAN中的影子内存检测的内存错误漏洞类型不同;在将主内存地址空间映射到新影子内存地址空间的过程中,将主内存访问地址添加或减去相应的固定偏移。
需要说明的是,原始ASAN会将程序的进程内存空间分为两部分:应用内存(或称为主内存)(Application Memory)空间和影子内存(Shadow Memory)空间。主内存属于程序进程,由程序进程进行使用。影子内存用于存放检测内存错误所需的元数据信息。具体来说,影子内存中存储了能够反映正常内存状态信息的元数据,而正常内存中存储的才是程序真正需要的数据。通过检测影子内存中的元数据,ASAN可以判定进程能否访问一片指定的主内存区域,从而发现内存访问错误。
如图3所示,位于最左边的是原始ASAN的内存布局,其影子内存空间分为第一影子内存(High Shadow-area)和第二影子内存(Low Shadow-area)保存不变;其应用内存空间分为原始第一主内存(High Application Memory)和原始第二主内存(Low ApplicationMemory)。其中整个内存空间被分成了高地址和低地址两个部分,第一影子内存和原始第一主内存均位于高地址部分,第二影子内存和原始第二主内存均位于低地址部分。第一影子内存和第二影子内存的地址会被映射到两个影子内存之间的间隙(Shadow Gap)。
如图3所示,位于中间的是本发明的程序进程内存空间布局,本发明将原始ASAN中的第一影子内存和第二影子内存保持不变,将原始第一主内存划分为第一主内存和第一新影子内存两个部分,将原始第二主内存划分第二主内存和第二新影子内存两个部分。第一新影子内存和第二新影子内存均可以用于检测未初始化变量使用、空指针解引用等漏洞。
如图4所示,原始ASAN中影子内存与主内存的映射关系为8:1,即8字节的主内存对应1个字节的影子内存。给定一段8字节的主内存,ASAN根据影子内存中1个字节的数值来确定对应主内存的能否访问及可访问范围:0表示8字节主内存全部可访问;负值表示主内存不可访问;0≤k≤8表示最前面的k字节是可寻址的,而剩下的8-k字节是不可寻址的。需要强调的是,影子内存也是内存中的一块区域,其中的数据仅仅反应其他正常主内存的访问状态信息,可以理解为正常内存的元数据,而正常内存中存储的才是程序真正需要的数据。
本发明在上面多重影子内存布局划分的基础上,设计面向多重影子内存布局的主内存与影子内存映射方法。其中,原有ASAN的主内存地址(Addr)到影子内存地址(ShadowAddr)映射方法不变,即右移3位后加上一个固定偏移(ShadowAddr=(Addr>>3)+偏移),从而把8字节的程序主内存映射为1字节的影子内存。除此之外,本发明新增了一种影子内存映射方法,以完成主内存到新影子内存区域的映射,从而可以实现更精细的元数据追踪,来检测未初始化变量使用、空指针解引用等内存错误。新影子内存映射(图3中虚线所示)实现了从主内存到新影子内存的bit-to-bit(位到位)的细粒度映射。具体的新影子内存映射计算如下:
当主内存访问地址Addr位于第二主内存时,为了将其对应的影子内存shadow位于第二新影子内存中,需要加上一个固定偏移(lowoffset);当主内存访问地址Addr位于第一主内存时,为了将其对应的影子内存shadow位于第一新影子内存内,需要减去一个固定偏移(highoffset)。
需要指出的是,通过上述多重影子内存的划分、映射,可以保留原有ASAN的影子内存使用以及相关漏洞检测功能;还可以通过在新影子内存中存储新的元数据信息(例如表示变量初始化状态等),来检测未初始化变量使用、空指针解引用、释放后使用等原始ASAN检测不到的漏洞。另外值得一提的是,新影子内存布局划分方案所预留的第一主内存和第二主内存依然有超过几十G的空间,完全可以满足实际测试需求。
进一步地,在具体实施时,在本发明实施例提供的上述内存错误检测方法中,步骤S4根据语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询多重影子内存中存储的元数据并插入安全检查,具体可以包括以下步骤:
第一步、在所有内存对象生命周期开始的代码位置处,设置对应的新影子内存中的元数据。
在实施中,基于前面提取的对象生命周期等语义信息,在所有对象生命周期开始的代码位置处,设置该对象对应新影子内存中的元数据,例如是否初始化等。这里主要设置两类信息:如图5所示,利用影子内存每个字节中的低两位存储对象的初始化状态标志,其中:“00”表示对象已经初始化;“01”表示对象已经初始化,但内容为空,即“NULL”;“10”表示对象未进行初始化。除去影子内存每个字节中的低两位,剩余的6个Bit位(即每个字节的高六位)被用来作为指针标签,用于释放后使用漏洞检测。具体来说就是,每一个对象(例如堆块)在分配时都为指向它的指针分配一个唯一的标签,用来标识指针和对象的关联关系,同时标记该标签的存活状态。在64位操作系统下,每个指针占8个字节,其相应的新影子内存大小也为8个字节,这里使用其中低4字节中存储该指针的标签。如图6所示,每个字节中低2位用于存放对象的初始化状态,低4个字节中剩余的6个比特,即总共24个比特来存放标签值。
第二步、识别出程序中所有的代码位置,并插入相应的代码,以传递源对象的元数据信息以及更新目标对象的元数据。
在实施中,识别出程序中所有的赋值、拷贝等代码位置,并插入相应的代码,从而传递源对象的元数据信息以及更新目标对象的元数据。举例来说,如果将一个已初始化的源对象S复制到一个未初始化的目标对象D,那么源对象S中的初始化状态也会被传递到目标对象D中,即D对应影子内存中的元数据会被标记为已初始化(即“00”)。
第三步、识别出程序中所有基于指针解引用的内存访问相关代码位置,并插入相应的内存来查询相应的元数据。
第四步、通过查询的元数据在程序中插入安全检查代码。
在实施中,安全检查指的是插入条件判断代码来在运行时检测未初始化对象访问、释放后使用等漏洞。特别的,针对越界访问内存漏洞,不需要基于元数据进行安全检查,而是在每一次内存访问或者地址计算时,都借助先前的值流、指针分析等程序分析手段,来定位要内存访问的源对象,并进行类型和大小分析,得出对象所占的内存大小范围,进而插入条件判断代码与实际内存访问地址进行比较,来检测漏洞。
进一步地,在具体实施时,在本发明实施例提供的上述内存错误检测方法中,步骤S5运行代码插桩后的程序,对内存错误漏洞进行检测,具体可以包括:使用相关命令行工具运行代码插桩后的程序;使用已有的测试输入样例或现有的输入生成方法,构造程序输入,执行相关程序路径,触发潜在的内存漏洞;程序运行过程中,在执行到代码插桩插入的安全检查代码时,借助语义解析信息进行设定条件判断,以检测是否发生越界访问错误、未初始化内存使用漏洞、空指针解引用错误、释放后重用漏洞、二次释放漏洞。
在实施中,运行插桩后的C/C++程序,程序运行过程中会执行插入的安全检查代码,从而检测是否发生相关内存漏洞。
在检测越界访问错误的过程中,检测此类型漏洞不需要依赖影子内存中的元数据,而是借助对象指向的程序语义信息,判断运行时的访问内存范围是否处于源对象所占的实际内存范围,如果为是,则继续执行;否则就检测为越界访问漏洞。举例来说,程序运行过程中,指针p需要访问地址addr=p+10处的内存,通过对象指向分析定位到指针p对应的源对象s为一个数组,其实际内存范围为[a,a+5],则插入的条件判断为addr>a&&addr<(a+5)。
在检测未初始化内存使用漏洞和空指针解引用错误的过程中,通过查询低两位的元数据,可以获取运行时内存访问相应的状态值。之后检查状态值是否为“00”,如果为“00”,那么该变量就为已初始化状态,如果不为“00”,那么根据Shadow值为“01”或“10”,报告空指针解引用漏洞和使用未初始化变量错误。
在检测释放后重用漏洞和二次释放漏洞的过程中,每当使用指针访问或释放内存时,就会去查询该指针相应对象存储在影子内存中的标签值,并进而查询该对象标签在堆块存活状态表中的状态。之后插入的安全检查会判断该对象是否是存活的状态,如果是则程序继续执行,否则检测为内存漏洞,并根据内存访问操作来进一步区分释放后重用漏洞和二次释放漏洞。
最后,如果安全检查,则没发生相关内存错误和漏洞,程序继续执行;如果安全检查未通过,那么程序崩溃,停止执行,并给出相应的内存错误和漏洞诊断信息,即漏洞类型、内存访问时所对应的源代码位置等。
在上述实施例中,对于内存错误检测方法进行了详细描述,本发明还提供内存错误检测装置、内存错误检测设备对应的实施例。需要说明的是,本发明从两个角度对装置部分的实施例进行描述,一种是基于功能模块的角度,另一种是基于硬件的角度。
图7为本发明的一实施例提供的内存错误检测装置的结构图。本实施例基于功能模块的角度,该装置包括:
程序分析模块10,用于提取源代码的基础程序信息;
语义解析模块11,用于对基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息;
内存划分模块12,用于将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间;
代码插桩模块13,用于根据语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询多重影子内存中存储的元数据并插入安全检查代码;
内存访问检测模块14,用于运行代码插桩后的程序,对内存错误漏洞进行检测。
在本发明实施例提供的上述内存错误检测装置中,可以通过上述五个模块的相互作用,借助多重影子内存中存储的元数据结合插入的安全检查代码,判定程序运行时是否有内存错误或漏洞,进而实现对程序内存访问行为的精准刻画和检查,可以同时检测多种类型的内存错误漏洞,还可以检测特定复杂的内存漏洞,降低内存错误的漏报率,大幅提升内存错误的检测精度。
由于装置部分的实施例与方法部分的实施例相互对应,因此装置部分的实施例请参见方法部分的实施例的描述,这里暂不赘述。并且具有与上述提到的内存错误检测方法相同的有益效果。
图8为本发明另一实施例提供的内存错误检测设备的结构图。本实施例基于硬件角度,如图8所示,内存错误检测设备包括:
存储器20,用于存储计算机程序;
处理器21,用于执行计算机程序时实现如上述实施例中所提到的内存错误检测方法的步骤。
其中,处理器21可以包括一个或多个处理核心,比如4核心处理器、8核心处理器等。处理器21可以采用数字信号处理器(Digital Signal Processor,DSP)、现场可编程门阵列(Field-Programmable Gate Array,FPGA)、可编程逻辑阵列(Programmable LogicArray,PLA)中的至少一种硬件形式来实现。处理器21也可以包括主处理器和协处理器,主处理器是用于对在唤醒状态下的数据进行处理的处理器,也称CPU;协处理器是用于对在待机状态下的数据进行处理的低功耗处理器。在一些实施例中,处理器21可以集成有图形处理器(Graphics Processing Unit,GPU),GPU用于负责显示屏所需要显示的内容的渲染和绘制。一些实施例中,处理器21还可以包括人工智能(Artificial Intelligence,AI)处理器,该AI处理器用于处理有关机器学习的计算操作。
存储器20可以包括一个或多个计算机可读存储介质,该计算机可读存储介质可以是非暂态的。存储器20还可包括高速随机存取存储器,以及非易失性存储器,比如一个或多个磁盘存储设备、闪存存储设备。本实施例中,存储器20至少用于存储以下计算机程序201,其中,该计算机程序被处理器21加载并执行之后,能够实现前述任一实施例公开的内存错误检测方法的相关步骤。另外,存储器20所存储的资源还可以包括操作系统202和数据203等,存储方式可以是短暂存储或者永久存储。其中,操作系统202可以包括Windows、Unix、Linux等。数据203可以包括但不限于上述所提到的内存错误检测方法所涉及到的数据等。
在一些实施例中,内存错误检测设备还可包括有显示屏22、输入输出接口23、通信接口24、电源25以及通信总线26。
本领域技术人员可以理解,图8中示出的结构并不构成对内存错误检测设备的限定,可以包括比图示更多或更少的组件。
本发明实施例提供的内存错误检测设备,包括存储器和处理器,处理器在执行存储器存储的程序时,能够实现如下方法:内存错误检测方法,效果同上。
最后,本发明还提供一种计算机可读存储介质对应的实施例。计算机可读存储介质上存储有计算机程序,计算机程序被处理器执行时实现如上述方法实施例中记载的步骤。
可以理解的是,如果上述实施例中的方法以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个计算机可读取存储介质中。基于这样的理解,本发明的技术方案本质上或者说对现有技术做出贡献的部分或者该技术方案的全部或部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,执行本发明各个实施例所述方法的全部或部分步骤。而前述的存储介质包括:U盘、移动硬盘、只读存储器(Read-Only Memory,ROM)、随机存取存储器(Random Access Memory,RAM)、磁碟或者光盘等各种可以存储程序代码的介质。
本发明提供的计算机可读存储介质包括上述提到的内存错误检测方法,效果同上。
还需要说明的是,在本说明书中,诸如第一和第二等之类的关系术语仅仅用来将一个实体或者操作与另一个实体或操作区分开来,而不一定要求或者暗示这些实体或操作之间存在任何这种实际的关系或者顺序。而且,术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、物品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、物品或者设备所固有的要素。在没有更多限制的情况下,由语句“包括一个……”限定的要素,并不排除在包括所述要素的过程、方法、物品或者设备中还存在另外的相同要素。
以上对本发明所提供的内存错误检测方法、装置、设备及介质进行了详细介绍。说明书中各个实施例采用递进的方式描述,每个实施例重点说明的都是与其他实施例的不同之处,各个实施例之间相同相似部分互相参见即可。对于实施例公开的装置而言,由于其与实施例公开的方法相对应,所以描述的比较简单,相关之处参见方法部分说明即可。应当指出,对于本技术领域的普通技术人员来说,在不脱离本发明原理的前提下,还可以对本发明进行若干改进和修饰,这些改进和修饰也落入本发明权利要求的保护范围内。

Claims (10)

1.一种内存错误检测方法,其特征在于,所述方法包括:
提取源代码的基础程序信息;
对所述基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息;
将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间;
根据所述语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询所述多重影子内存中存储的元数据并插入安全检查代码;
运行代码插桩后的程序,对内存错误漏洞进行检测。
2.根据权利要求1所述的内存错误检测方法,其特征在于,所述提取源代码的基础程序信息,包括:
接收所述源代码,利用LLVM编译器构建程序的抽象语法树;
利用所述LLVM编译器编译所述源代码,并将编译后的所述源代码转换为LLVM IR指令;
对所述LLVM IR指令进行控制流分析和静态值流分析,分别获取控制流信息和构造程序的值流图,以提取所述源代码的基础程序信息。
3.根据权利要求2所述的内存错误检测方法,其特征在于,所述对所述基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息,包括:
根据获取的所述控制流信息,对与函数调用相关的所述LLVM IR指令进行分析,获得调用点的直接调用关系、间接调用关系、目标函数名称、参数类型及数量、返回值及返回值类型;
在变量生命周期分析过程中,创建局部变量的AllocaInst进行插桩分析,获得变量的创建点;
借助所述抽象语法树对VarDecl节点所属的域进行分析,并在域结束时插入指令,以标记变量的销毁点;
在内存对象生命周期分析过程中,开始于内存分配的调用点,结束于内存释放的调用点;
将变量和内存对象生命周期的分析结果保存至运行时库的全局数组中,并随着程序运行进行动态更新;
对内存对象进行边界分析,得到不同类型对象所占的内存范围;
对变量进行指向分析,得到设定指针变量指向的内存对象集合。
4.根据权利要求3所述的内存错误检测方法,其特征在于,所述对变量进行指向分析,得到设定指针变量指向的内存对象集合,包括:
在构造的所述值流图上定位设定指针变量所在的节点,迭代分析所述节点的前驱节点,直至找到以AllocaInst创建的临时变量、静态声明的全局变量和堆上分配的临时变量,结合指针别名分析,筛选出对应的内存对象。
5.根据权利要求4所述的内存错误检测方法,其特征在于,所述将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间,包括:
将原始ASAN中的应用内存空间划分为所述主内存和新影子内存;所述新影子内存和所述原始ASAN中的影子内存组成所述多重影子内存;所述新影子内存检测的内存错误漏洞类型与所述原始ASAN中的影子内存检测的内存错误漏洞类型不同;
在将主内存地址空间映射到所述新影子内存地址空间的过程中,将主内存访问地址添加或减去相应的固定偏移。
6.根据权利要求5所述的内存错误检测方法,其特征在于,所述根据所述语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询所述多重影子内存中存储的元数据并插入安全检查,包括:
在所有内存对象生命周期开始的代码位置处,设置对应的所述新影子内存中的元数据;
识别出程序中所有的代码位置,并插入相应的代码,以传递源对象的元数据信息以及更新目标对象的元数据;
识别出程序中所有基于指针解引用的内存访问相关代码位置,并插入相应的内存来查询相应的元数据;
通过查询的元数据在程序中插入安全检查代码。
7.根据权利要求6所述的内存错误检测方法,其特征在于,所述运行代码插桩后的程序,对内存错误漏洞进行检测,包括:
使用相关命令行工具运行代码插桩后的程序;
执行相关程序路径,触发潜在的内存漏洞;
程序运行过程中,在执行到代码插桩插入的安全检查代码时,借助所述语义解析信息进行设定条件判断,以检测是否发生越界访问错误、未初始化内存使用漏洞、空指针解引用错误、释放后重用漏洞、二次释放漏洞。
8.一种内存错误检测装置,其特征在于,所述装置包括:
程序分析模块,用于提取源代码的基础程序信息;
语义解析模块,用于对所述基础程序信息中函数、变量、内存对象的高层语义信息进行解析,得到语义解析信息;
内存划分模块,用于将程序进程内存空间进行布局划分,得到主内存和用于检测不同类型内存错误漏洞的多重影子内存,并将主内存地址空间映射到多重影子内存地址空间;
代码插桩模块,用于根据所述语义解析信息在程序中对应的操作位置上进行代码插桩,以设置、更新和查询所述多重影子内存中存储的元数据并插入安全检查代码;
内存访问检测模块,用于运行代码插桩后的程序,对内存错误漏洞进行检测。
9.一种内存错误检测设备,其特征在于,所述设备包括:
存储器,用于存储计算机程序;
处理器,用于执行所述计算机程序时实现如权利要求1至7任一项所述的内存错误检测方法的步骤。
10.一种计算机可读存储介质,其特征在于,所述计算机可读存储介质上存储有计算机程序,所述计算机程序被处理器执行时实现如权利要求1至7任一项所述的内存错误检测方法的步骤。
CN202410006515.6A 2024-01-02 2024-01-02 内存错误检测方法、装置、设备及介质 Pending CN117785540A (zh)

Priority Applications (1)

Application Number Priority Date Filing Date Title
CN202410006515.6A CN117785540A (zh) 2024-01-02 2024-01-02 内存错误检测方法、装置、设备及介质

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
CN202410006515.6A CN117785540A (zh) 2024-01-02 2024-01-02 内存错误检测方法、装置、设备及介质

Publications (1)

Publication Number Publication Date
CN117785540A true CN117785540A (zh) 2024-03-29

Family

ID=90387176

Family Applications (1)

Application Number Title Priority Date Filing Date
CN202410006515.6A Pending CN117785540A (zh) 2024-01-02 2024-01-02 内存错误检测方法、装置、设备及介质

Country Status (1)

Country Link
CN (1) CN117785540A (zh)

Similar Documents

Publication Publication Date Title
US11061833B2 (en) Apparatus and method for handling page protection faults in a computing system
Stepanov et al. MemorySanitizer: fast detector of uninitialized memory use in C++
US8762797B2 (en) Method and apparatus for detecting memory access faults
US5590329A (en) Method and apparatus for detecting memory access errors
US8352921B2 (en) Static analysis defect detection in the presence of virtual function calls
US9535613B2 (en) Hardware and software methodologies for detecting illegal memory address of a memory access operation
US8578357B2 (en) Endian conversion tool
US20090150863A1 (en) Type checking for object-oriented programming languages
CN111506500B (zh) 内存泄露检测方法、装置、电子设备及可读存储介质
US9250939B2 (en) Information processing device, profile target determining program, and method
CN111183413B (zh) 用于在计算机中执行程序的方法
Chen et al. A source-level instrumentation framework for the dynamic analysis of memory safety
Banerjee et al. Sound garbage collection for C using pointer provenance
CN117785540A (zh) 内存错误检测方法、装置、设备及介质
CN114443418A (zh) 一种基于硬件虚拟化的riscv内存溢出漏洞检测方法及装置
CN114153451A (zh) 一种利用数据流分析算法分析c代码中的内存安全的方法
CN114065208A (zh) 一种面向堆内存错误的检测方法及装置
Cameron et al. A virtual machine for the Insense language
Runnalls Aspects of CXXR internals
Boehm et al. Garbage collection in the next C++ standard
Geffken et al. Side effect monitoring for Java using bytecode rewriting
Erhardt et al. The final Frontier: Coping with Immutable Data in a JVM for Embedded Real-Time Systems
Bond Diagnosing and tolerating bugs in deployed systems
Gerasimov et al. Case study: Source code static analysis for performance issues detection
Kevin Improving on C with Rust An analysis of Rusts preventative abilities

Legal Events

Date Code Title Description
PB01 Publication
PB01 Publication
SE01 Entry into force of request for substantive examination
SE01 Entry into force of request for substantive examination