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

陈金宝 等: DBI-Go: 动态插桩定位 Go 二进制的非法内存引用                                             2587


                 行时崩溃产生的原因, 从而         Go  的  GC  的崩溃输出几乎不能提供有效的信息帮助开发者定位问题. 像前述的
                 issue#44614  从  Go1.14  便开始出现, 直至  Go1.17  发布前才被修复, 影响了  Go1.14.x、Go1.15.x、Go1.16.x  这 3 个
                 大版本.


                   年份  issue 号  版本      备注
                   2022  54247  go1.17  堆指向栈的问题
                   2022  53289  go1.18  堆指向栈的问题
                   2022  51481  go1.18  堆指向栈的问题
                   2022  52008  go1.15  堆指向栈的问题
                   2021  47415  go1.16  CGO 相关逃逸问题
                   2021  49755  go1.16  堆指向栈的问题
                   2021  47276  go1.16  堆指向栈的问题
                   2021  44614  go1.14至1.16 堆指向栈的问题
                   2021  43818  go1.17  寄存器传参问题
                   2020  41635  go1.16  逃逸调试信息错误                    5
                   2020  42944  go1.16  堆指向栈的问题
                                         个使用动态二进制插桩方式分析
                   2019  31573  go1.13  逃逸带来的 runtime 问题            4
                   2019  32959  go1.13  逃逸带来的编译问题                  issue 数量  3
                   2018  29000  go1.11至1.12 逃逸带来的 runtime 问题
                   2018  29353  go1.13  逃逸带来的 runtime 问题            2
                   2018  26987  go1.12  逃逸带来的 runtime 问题
                   2017  23045  go1.11  逃逸带来的 uintptr 问题            1
                                                                      2017  2018  2019  2020  2021  2022
                  issue 链接: https://github.com/golang/go/issues/                   年份
                  图 1    社区中 Go 逃逸错误相关 issues (不完全统计)          图 2    社区中  Go  逃逸错误相关   issues 数量变化趋势

                    针对  Go 程序和/或   Go  语言编译器的漏洞检测, 目前多集中在对            Go  程序的并发、竞争检测方面         [17−19] , 与  Go
                 语言编译器的逃逸分析相关的研究屈指可数, 仅有                Wang  等人的工作   [20] 使得一些对象可以绕过      Go  语言编译器的
                 逃逸分析, 从而节省堆内存的使用. 目前尚无相关工作来寻找经                   Go  语言编译器编译出的代码中的错误内存引用,
                 学术界对此的研究缺失. 同时, 目前         Go  官方对逃逸分析正确性的测试手段也较为有限, 难以辅助开发人员对逃逸
                 分析算法进行进一步的优化或重构.
                    为了有效检测编译器生成的代码是否存在可能引起运行时崩溃的非法内存引用, 在产品上线前就能及时发现
                 问题, 避免产品在实际生产环境中出现崩溃, 造成损失, 也为了辅助开发人员对内存优化相关算法, 如逃逸分析进
                 行优化和重构, 验证算法的正确性, 本文提出一种结合静态分析和动态插桩检测                          Go  二进制中可能导致非法内存
                 引用的   store 指令的方法, 并基于 Pin  [21] 实现了工具原型   DBI-Go, 它可以在不修改     Go 编译运行时系统的情况下对
                 Go  二进制程序进行检测, 具有较好的适用性. 该工具权衡静态分析和动态插桩, 并结合 Go 的语言特性, 大大减少
                 了误报率和插桩带来的额外开销.
                    本文的主要贡献点包括以下内容.
                    • 对  Go  二进制程序进行抽象, 并基于此抽象分析提出两条判定非法内存引用的判定规则. 非法内存引用由二
                 进制程序中将不当的地址通过          store 指令写入: (1) 将栈地址存入栈外; (2) 将较浅栈帧中的对象的地址存入较深栈帧.
                    • 提出了  DBI-Go——第   1                           Go  二进制中潜在非法内存引用的工具. DBI- Go
                 可以将   Go  的二进制可执行文件与       Go  语义以及  Go  的运行时管理系统关联起来, 有着较低的误报率, 且在大多数
                 情况  (93.3%) 有不超过  2  倍的额外运行时开销. DBI-Go     还可以精准给出违例的发生位置, 帮助快速定位问题.
                    • 实验结果表明, DBI-Go 可以检测出       Go 社区中所有已知的逃逸相关         issue, 有着较高的漏洞覆盖率. 同时       DBI-
                 Go  还发现了一个目前      Go  社区未知的问题. 该问题已经在         golang-nuts 中得到 Go  官方维护人员的确认      (https://
                 groups.google.com/g/golang-nuts/c/YZVFzwnPixM), 并已向社区提交  issue 有待  Go 官方的进一步修复  (https://github.
                 com/golang/go/issues/61730).
                    • 对  DBI-Go  的实际应用还表明, 其可以辅助开发人员对           Go  逃逸分析算法进行优化和重构, 帮助找到新逃逸
   6   7   8   9   10   11   12   13   14   15   16