arkcompiler_runtime_core/libark_defect_scan_aux
meeting-meeting a4893dc21d Handle compile build alerts
Issue: https://gitee.com/openharmony/arkcompiler_runtime_core/issues/IAW32C

Signed-off-by: ah <liangahui@h-partners.com>

Change-Id: I15e476695551f8ec0d1a247677e4b8a67f93b2f3
2024-10-10 17:42:48 +08:00
..
include Defect scan adapt ecma class and sendable class 2024-07-25 19:32:38 +08:00
templates Adapt the lib of defect scan to isa refactoring 2022-10-26 09:38:32 +08:00
tests/unittest Handle compile build alerts 2024-10-10 17:42:48 +08:00
abc_file.cpp Defect scan adapt ecma class and sendable class 2024-07-25 19:32:38 +08:00
BUILD.gn 5.0 component improvement 2024-03-30 20:33:23 +08:00
callee_info.cpp Bugfix for defect scan api 2024-01-07 13:33:55 +00:00
class.cpp Update version for Function name with scopes 2024-05-25 16:04:00 +08:00
function.cpp Support defect scan api for merge abc - part1 2023-12-30 21:14:53 +08:00
graph.cpp Fix recursive instructions in AbcFile::ResolveInstCommon 2023-12-20 22:40:19 +08:00
module_record.cpp Refactor libark_defect_scan_aux test framework and add async function test 2023-12-21 21:00:43 +08:00
README.md add compilation support for libark_defect_scan_aux on both Windows and macOS 2024-03-11 09:43:42 +00:00

基于方舟字节码文件的安全扫描接口

1.背景

JS/TS 应用中对关键敏感函数的调用参数如果直接来自用户的外部输入没有进行有效性判断容易导致注入攻击或者应用程序崩溃。因此需要提供基于方舟字节码文件Ark ByteCode, 简称abc)的安全漏洞扫描工具,以提高应用的可靠性、安全性。

在此,我们为安全漏洞扫描工具提供基于abc文件的分析接口,以供分析相关函数的调用链和参数信息,进行漏洞检测。

2.原理

工具的大致实现流程如下:

flowchart LR;
  A((.abc file))-->B[Iterate All Methods];
  A((.abc file))-->C[Parse Module Import/Export Entry];
  B[Iterate All Methods]-->D[Generate Method CFG/DFG];
  D[Generate Method CFG/DFG]<-->G[Compiler IRBuilder];
  D[Generate Method CFG/DFG]-->E[Extract Defined Function/Class];
  D[Generate Method CFG/DFG]-->F[Extract Callee Function/ Extract Class Inheritance Info];
  C[Parse Module Import/Export Entry]-->F[Extract Callee Function/ Extract Class Inheritance Info];
  E[Extract Defined Function/Class]-->F[Extract Callee Function/ Extract Class Inheritance Info];

对一个abc文件我们会解析它导入和导出的模块间信息遍历所有函数调用IR Builder的接口生成所有函数的控制流图和数据流图。根据生成图以及模块间的导入导出信息构建函数之间的调用关系以及类的继承关系并提供相应的接口。

3.使用方法

3.1 支持平台说明

安全扫描工具当前支持在Linux/MacOS平台上编译和运行以及在Linux平台上交叉编译能够在Windows平台上运行的可执行程序。

3.2 自定义代码

我们在runtime_core/libark_defect_scan_aux/tests/unittest/defect_scan_aux_demo.cpp提供了简单的示例代码,其中指定了abc文件路径(例如,test.abc),开发者可根据需求修改该示例代码文件,然后编译运行。

3.3 编译命令

Linux

./build.sh --product-name rk3568 --build-target ark_host_linux_defectscanaux_unittest

out/rk3568/clang_x64/arkcompiler/runtime_core目录下会生成示例文件对应的可执行程序文件。

Windows

./build.sh --product-name rk3568 --build-target ark_host_win_defectscanaux_unittest

out/rk3568/mingw_x86_64/arkcompiler/runtime_core目录下会生成示例文件对应的可执行程序文件。

Mac M1

cd ${OpenHarmony}

./prebuilts/build-tools/darwin-arm64/bin/gn gen ./out/mac_arm64 \
--root=. \
--dotfile=./arkcompiler/toolchain/build/compile_script/.gn \
--args="target_os=\"mac\" target_cpu=\"arm64\" is_debug=false"

./prebuilts/build-tools/darwin-arm64/bin/ninja  -d keeprsp -C out/mac_arm64 ark_host_defectscanaux_tools -k 1

out/mac_arm64/arkcompiler/runtime_core目录下会生成示例文件对应的可执行程序文件。

Mac x64

cd ${OpenHarmony}

./prebuilts/build-tools/darwin-x86/bin/gn gen ./out/mac_x64 \
--root=. \
--dotfile=./arkcompiler/toolchain/build/compile_script/.gn \
--args="target_os=\"mac\" target_cpu=\"x64\" is_debug=false"

./prebuilts/build-tools/darwin-x86/bin/ninja  -d keeprsp -C out/mac_x64 ark_host_defectscanaux_tools -k 1

out/mac_x64/arkcompiler/runtime_core/目录下会生成示例文件对应的可执行程序文件。

3.4 如何生成abc文件

3.4.1 使用命令行

参考《es2panda使用方式》编译js/ts文件生成abc文件。

3.4.2 使用DevEco Studio

通过DevEco Studio编译应用编译成功后解压应用hap包,找到其中的abc文件。

3.5 执行扫描

将需要扫描的abc文件放到示例代码中指定的文件路径后,执行示例代码对应的可执行程序即可。

以 Linux 为例

cd out/rk3568/clang_x64/arkcompiler/runtime_core
./defect_scan_aux_demo

4.接口说明

4.1 AbcFile

接口名及参数 描述
static std::unique_ptr<const AbcFile> Open(std::string_view abc_filename) 根据文件名打开方舟字节码文件并返回该文件
bool IsMergeAbc() const 返回方舟字节码文件是否为合并格式
const std::set<std::string> GetFileRecordList() const 若为合并abc返回所有文件描述名
size_t GetFileRecordCount() const 若为合并abc返回abc中的文件个数
const std::string &GetAbcFileName() const 返回方舟字节码文件的名称
const std::vector<std::shared_ptr<Class>> &GetClassList() const 返回包含所有类的列表
size_t GetDefinedFunctionCount() const 返回定义的函数个数
size_t GetDefinedClassCount() const 返回定义的类的个数
const Function *GetFunctionByName(std::string_view func_name) const 根据名称返回指定函数
const Function *GetExportFunctionByExportName(std::string_view export_func_name, std::string_view record_name = "") const 根据导出名返回指定的导出函数若为合并abc需指定文件描述名
const Class *GetClassByName(std::string_view class_name) const 根据类名返回指定类
const Class *GetExportClassByExportName(std::string_view export_class_name, std::string_view record_name = "") const 根据导出名返回指定的导出类若为合并abc需指定文件描述名
size_t GetLineNumberByInst(const Function *func, const Inst &inst) const 根据指令返回该指令对应源码的行号
std::string GetLocalNameByExportName(std::string_view export_name, std::string_view record_name = "") const 根据变量的导出名返回其本地的名称若为合并abc需指定文件描述名
std::string GetImportNameByExportName(std::string_view export_name, std::string_view record_name = "") const 根据变量的导出名返回其导入的名称若为合并abc需指定文件描述名
std::string GetModuleNameByExportName(std::string_view export_name, std::string_view record_name = "") const 根据变量的导出名返回导入该变量的模块名若为合并abc需指定文件描述名
std::string GetModuleNameByLocalName(std::string_view local_name, std::string_view record_name = "") const 根据变量的本地名返回导入该变量的模块名若为合并abc需指定文件描述名
std::string GetImportNameByLocalName(std::string_view local_name, std::string_view record_name = "") const 根据变量的本地名返回该变量的导入名若为合并abc需指定文件描述名

4.2 Function

接口名及参数 描述
const std::string &GetFunctionName() const 返回函数名
const AbcFile *GetAbcFileInstance() const 返回该函数所在的方舟字节码文件
const std::string &GetRecordName() const 若为合并abc返回该函数所在的文件描述名
const Graph &GetGraph() const 返回该函数的构图
const Class *GetClass() const 返回定义该函数的类
const Function *GetParentFunction() const 返回定义该函数的函数
uint32_t GetArgCount() const 返回参数个数
size_t GetDefinedClassCount() const 返回函数中定义的类的个数
size_t GetDefinedFunctionCount() const 返回函数中定义的函数的个数
size_t GetCalleeInfoCount() const 返回调用信息的个数
const CalleeInfo *GetCalleeInfoByCallInst(const Inst &call_inst) const 根据调用指令返回调用信息

4.3 Class

接口名及参数 描述
const std::string &GetClassName() const 返回类名
const AbcFile *GetAbcFileInstance() const 返回该类所在的方舟字节码文件
const std::string &GetRecordName() const 若为合并abc返回该类所在的文件描述名
Function *GetDefiningFunction() const 返回定义该类的函数
size_t GetMemberFunctionCount() const 返回成员函数的数量
const Function *GetMemberFunctionByName(std::string_view func_name) const 根据名称返回成员函数
const std::vector<const Function *> &GetMemberFunctionList() const 返回所有成员函数
const Class *GetParentClass() const 返回父类
const std::string &GetParentClassName() const 返回父类名
const std::string &GetParClassExternalModuleName() const 返回导入父类的模块名
const std::string &GetParClassGlobalVarName() const 返回父类的全局变量名

4.4 CalleeInfo

接口名及参数 描述
int GetCalleeArgCount() const 返回该被调者的参数个数
const Inst &GetCallInst() const 返回该被调者相关的调用指令
const Function *GetCaller() const 返回该被调者的调用者
const Class *GetClass() const 返回该被调者所在的类
const Function *GetCallee() const 返回该被调者的对应函数
const std::string &GetFunctionName() const 返回该被调者的函数名
const std::string &GetClassName() const 返回该被调者所在的类名
const std::string &GetExternalModuleName() const 返回导入该被调者的模块名
const std::string &GetGlobalVarName() const 返回该被调者所在的全局变量名

4.5 Graph

接口名及参数 描述
BasicBlock GetStartBasicBlock() const 返回第一个基块
BasicBlock GetEndBasicBlock() const 返回最后一个基块
std::vector GetBasicBlockList() const 返回所有基块
void VisitAllInstructions(const InstVisitor visitor) const 遍历所有指令

4.6 BasicBlock

接口名及参数 描述
std::vector<BasicBlock> GetPredBlocks() const 返回前驱基块
std::vector<BasicBlock> GetSuccBlocks() const 返回后继基块
std::vector<Inst> GetInstList() const 返回基块中所有指令

4.7 Inst

接口名及参数 描述
InstType GetType() const 返回指令类型
bool IsInstStLexVar() const 返回指令是否为stlexvar类型
bool IsInstLdLexVar() const 返回指令是否为ldlexvar类型
bool IsInstStGlobal() const 返回指令是否为stglobalvar类型
bool IsInstLdGlobal() const 返回指令是否为ldglobalvar类型
uint32_t GetPc() const 返回指令的程序计数器
BasicBlock GetBasicBlock() const 返回该指令所属的基块
Graph GetGraph() const 返回该指令所属的基块所属的图
std::vector<Inst> GetInputInsts() const 返回该指令的输入指令
std::vector<Inst> GetUserInsts() const 返回将该指令作为输入的指令

5.已知问题

5.1 Try catch块包含throw语法的场景中构图存在问题

对于如下在Try catch块中包含throw语法的示例,

try {
  throw 1;
} catch (e) {
}

正确的基块结构简化后如下所示,即Throw Block的后继为Catch Block

+----------------+       +----------------+
|   Start Block  | ----> |  Throw Block   |
+----------------+       +----------------+
                                 |
                                 v
                         +----------------+
                         |  Catch Block   |
                         +----------------+
                                 |
                                 v
                         +----------------+
                         |   End Block    |
                         +----------------+

但是,当前实现会将Throw Block指向当前函数的结束块,导致某些场景下Catch Block块没有前驱,简化后的基块结构如下所示:

+----------------+       +----------------+
|   Start Block  | ----> |  Throw Block   | ------
+----------------+       +----------------+      |
                                                 |
                         +----------------+      |
                         |  Catch Block   |      |
                         +----------------+      |
                                 |               |
                                 v               |
                         +----------------+      |
                         |    End Block   | <-----
                         +----------------+

5.2 接口所提供的类的继承关系和函数调用关系等不完全准确

由于不存在完美的静态分析,本工具所提供的类的继承关系和函数调用关系接口(如GetCallerGetCalleee)等为尽力分析的结果,但可能并不完全准确。

开发者可根据构图和指令等确定的信息,定制化进行更准确地漏洞扫描分析。