Page 28 - 《软件学报》2024年第6期
P. 28

2604                                                       软件学报  2024  年第  35  卷第  6  期


                    • 有待进一步大规模测试. 目前         DBI-Go  在真实世界开源项目上的测试尚未发现问题, 只在               18  个仓库上进行
                 了测试, 覆盖面不足. 未来期望能够进行更大规模的测试, 以期找出开源仓库中的问题, 帮助改善                            Go  语言软件的
                 内存安全性, 提升其可靠性.

                 6   相关工作


                 6.1   动态二进制分析
                    动态二进制分析框架, 如        Pin [21] 、Valgrind [42] 、DynamoRIO  [43] , 可以用于插桩任意指令来执行动态分析. 这些
                 工具为研究者们的分析带来了很大的便利. Amitabha 等人              [44] 研究了如何有效地插桩      x86  机器码中的内存访问以
                 支持软件事务内存和分析. Patil 等人       [45] 基于 Pin  设计了  Pinplay, 一个基于执行捕获和确定性重放的并行程序分析
                 框架. Zhong  等人  [17] 基于  DynamoRIO  设计了一个动态二进制工具, 用于检测      Go  中的并发问题.
                    基于动态二进制分析的漏洞检测包括前面提到的并发漏洞分析、污点分析                              [46] 、逆向工程  [47]  和执行重
                 放     [48] 等.
                                               , 用于检测数据竞争的
                 6.2   内存漏洞检测
                    目前已有的内存相关的漏洞检测工作主要是针对                  C/C++这种具有弱静态类型系统的编程语言来进行的, 因为
                 强制类型转换、任意指针的存在使得悬空引用、边界溢出等内存漏洞更容易发生, Song                           等人于   2013  年  [30] 通过系
                 统性地建立内存损坏的一般模型, 揭示了             C/C++容易遭受内存漏洞的主要原因. 现有的内存漏洞检测工作依赖于
                 静态程序分析或动态程序分析来进行.
                    静态检测: 分析程序      (源) 代码, 并生成对于所有可能的代码执行都是保守正确的结果. 静态检测的一部分工
                 作基于形式化验证: Clarke 等人提出了一种使用有界模型检查                 (BMC) 对  ANSI-C  程序进行形式化验证的工具       [49]
                 来检测内存问题. 更多的静态检测工作则是基于符号执行: CUTE                  [50] 通过结合符号执行和具体执行, 将内存图作为
                 输入来执行自动化测试; EXE        [51] 是利用符号执行来自动生成导致实际代码崩溃的输入, 进行快速的错误定位;
                 Klee [52] 则是通过符号执行来自动生成测试.
                    动态检测: 通过分析单个程序的执行, 并输出仅对单个运行有效的精确分析结果. 消毒器 (sanitizer)——静态
                 插入运行时监视器, 并在运行时进行检测——是动态检测工具的典型代表. Serebryany                        等人在   2012  年提出了
                 AddressSanitizer (ASAN) [28] , 它通过插桩应用程序中的内存访问操作, 在运行时建模影子内存, 从而能识别缓冲区
                 溢出、悬垂指针、内存泄漏等内存漏洞. 由于它能够在不牺牲完备性的情况下实现了检测效率, AddressSanitizer
                 已经被集成到许多常用的编译工具链中, 包括针对                C/C++的编译器    GCC、LLVM, 以及 Go 语言编译器. 但      ASAN
                 目前在   Go  编译器中的使用场景受限, 仅能检测          Go  语言中和   C  语言进行交互的相关代码上的内存错误             [53] , 对于
                 纯  Go  语言代码尚不支持. ASAN    与  DBI-Go  的相同点在于二者都是基于插桩, ASAN          是在编译时插桩, DBI-Go    是
                 基于动态二进制插桩. 区别在于          ASAN  的设计目的是检测诸如缓冲区溢出之类的通用的内存漏洞, 不能检测                       Go
                 中违反   Go  逃逸不变式的    store; 且其所能检测的内存漏洞只有在被触发时才能发现                (如内存被释放、指针被解引
                 用时), 此时  Go  程序可能已经崩溃. 而     DBI-Go  则是针对   Go  语言专门设计, 利用    Go  的逃逸不变式这一独特特性,
                 可以在内存隐患发生的第一现场就报错              (比如将栈地址存入堆时). 因此即使          ASAN  可以支持纯     Go  的代码, 其也
                 无法代替   DBI-Go. 类似地, 还有许多使用类似方式进行针对其他问题检测的漏洞检测工具, 如用于检测未初始化
                 内存的使用情况的 MemorySanitizer    [54]               ThreadSanitizer [55] , 利用动态内存检查来检测对象有
                 效性的   EffectiveSan [56]  等. Song  等人  [29]  则是在  2019 年对  Sanitizing  这种技术进行了对比总结, 描述了不同的
                 Sanitizer 工具的性能和可扩展性. 此外, 还有部分工作通过修改运行时系统来实现运行时检测, 如                          DieHard [57] 、
                 SoftBound [58] .

                 6.3   Go 的漏洞检测
                    目前针对    Go  的漏洞检测已有许多工作. Lange 等人        [19] 为  Go  中的消息传递机制进行建模, 为     Go  的消息传递
                 机制提出了一个验证框架. Lauinger 等人        [33] 提出了  go-safer, 一种全新的静态分析工具, 用来识别      Go  源代码中对
   23   24   25   26   27   28   29   30   31   32   33