当前位置: 首页 > 工具软件 > go-fuzz > 使用案例 >

FUZZ测试总结

魏晨
2023-12-01

FUZZ测试总结

Fuzzing简介

模糊测试(fuzzing test)是一种软件测试技术,其核心思想是将自动或半自动生成的随机数据输入到一个程序中,并监视程序异常,如崩溃,断言(assertion)失败,以发现可能的程序错误,比如内存泄漏,访问越界等。

Fuzzing测试框架使用了LLVM编译器框架中的libFuzzer作为Fuzzing引擎进行构建,libFuzzer是一个基于LLVM编译时路径插桩,可以对被测库API进行路径引导测试的Fuzzing引擎。

使用Fuzzing测试框架,需要完成fuzzer测试用例初始化、fuzzer用例编写、fuzzer用例编译和fuzzer用例执行几步。

Fuzzing测试关注的风险接口

开发者应该了解自身模块的接口数据输入是基于不可信的来源输入,特别是针对

  • 解析处理远程发送来的TCP/UDP或者蓝牙等协议数据
  • 通过复杂的文件解码处理等,包括音视频、图片解码、解压缩等
  • IPC跨进程的数据输入处理

通过Fuzzing的覆盖引导能力,可以有效的探测和消减外部输入造成的内存安全问题,也可以极大的增强系统稳定性。

环境配置

将toolchains添加在环境变变中:

在cmd中用hdc_std shell检测

安装Linux扩展组件readline,安装命令如下:

sudo apt-get install libreadline-dev

安装setuptools插件,安装命令如下:

pip3 install setuptools

安装paramiko插件,安装命令如下:

pip3 install paramiko

安装python的rsa插件,安装命令如下:

pip3 install rsa

安装串口插件pyserial,安装命令如下:

pip3 install pyserial

如果设备仅支持串口输出测试结果,则需要安装NFS Server

  • Windows环境下安装,例如安装haneWIN NFS Server1.2.50。
  • Linux环境下安装,安装命令如下:
sudo apt install nfs-kernel-server

启动测试框架

root@ubuntu:/home/OpenHarmony/test/developertest#

 ./start.sh 

Please select the current tested product form:

  1. xxx

  2. xxx

  3. xxx

(输入对应数字的产品;回车)

或者

在Windows下点击start.bat;

输入输入对应数字的产品;回车

生成测试目录

Fuzz用例初始化

>>> gen -t FUZZ -fn  xxx_fuzzer -dp fuzztest/

>>> gen -t FUZZ -fn xxx_fuzzer -dp fuzztest/

>>> quit

在Windows下:
>>> gen -t FUZZ -fn xxx_fuzzer -dp D:\xxx\xxx

>>> gen -t FUZZ -fn xxx_fuzzer -dp D:\file_work

执行gen命令用于fuzzer源文件生成,会自动生成fuzzer源文件、fuzzer配置文件和corpus语料,目录结构如下:

xxx_fuzzer/
├── corpus                       			 # Fuzz语料目录
│   ├── init                     			 # Fuzz语料
├── BUILD.gn                      			 # Fuzz用例编译配置
├── xxx_fuzzer.cpp      # Fuzz用例源文件
├── xxx.h        # Fuzz用例头文件
├── project.xml                  			 # Fuzz选项配置文件

命令参数说明,参数可以指定fuzzer名称和fuzzer路径

gen -t TESTTYPE -fn FUZZERNAME -dp DIRECTORYPATH
参数描述说明备注
-ttesttype测试类型目前仅支持"FUZZ"
-fnfuzzernamefuzzer名称为显式区分Fuzz用例,名称必须以测试套前缀小写 + _fuzzer形式命名
-dpdirpathfuzzer生成路径路径不存在则自动创建目录

gen命令的参数-t、-fn和-dp均为必选项;

Fuzz用例编写

注意:更改每个文件注释里的年份为当年!!!

源文件编写

Fuzz用例主要在{fuzzer名称}.cpp源文件中,一个Fuzz用例仅支持一个接口进行fuzz测试。

源文件包含两个接口:

接口说明
LLVMFuzzerTestOneInputFuzz入口函数,由Fuzz框架调用
DoSomethingInterestingWithMyAPI被测试接口,实现各业务被测试逻辑

说明: DoSomethingInterestingWithMyAPI接口名称允许依据业务逻辑修改。两接口参数data和size为fuzz测试标准化参数,不可修改。

#include <stddef.h>
#include <stdint.h>
#include "xxx_fuzzer.h"

void OHOS::xxx::xxxTest(const uint8_t* data, size_t size)
{
    if ((data == nullptr) || (size <= 0)) {
        return;
    }

    XXX xxx;
    size -= sizeof(uint32_t);
    xxx.WriteBuffer(data + sizeof(uint32_t), size);
    xxx.RewindRead(0);

    XXXX xxxx;

    xxxx.Marshalling(xxx);
    xxxx.Unmarshalling(xxx);
}

/* Fuzzer entry point */
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    /* Run your code on data */
    OHOS::xxx::xxxxTest(data, size);
    return 0;
}

头文件编写

#ifndef OHOS_xxx_FUZZER_H
#define OHOS_xxx_FUZZER_H

#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <unistd.h>

#define FUZZ_PROJECT_NAME "xxx_fuzzer"

namespace OHOS::xxx{
void xxxTest(const uint8_t* data, size_t size);
}

#endif

BUILD.gn编写

#####################hydra-fuzz###################
import("//build/config/features.gni")
import("//build/test.gni")
module_output_path = "xxx/xxx"

##############################fuzztest##########################################
ohos_fuzztest("xxxFuzzTest") {
  module_out_path = module_output_path

  fuzz_config_file =
    "//foundation/xxx/xxx/xxx_fuzzer"

  include_dirs = [
    "//foundation/xxx/xxx/test/fuzztest"
  ]
  cflags = ["-g","-O0","-Wno-unused-variable","-fno-omit-frame-pointer"]
  sources = [
    "xxx_fuzzer.cpp",
  ]
  deps = [
    "//foundation/xxx/xxx:xxx",
    "//utils/native/base:utils"
  ]
  external_deps = [
    "xxx:xxx",
  ]
}

group("fuzztest") {
  testonly = true
  deps = []
  deps += [
    # deps file
    ":xxxFuzzTest",
  ]
}

基于[ohos_fuzztest]配置Fuzz模板,例如:

ohos_fuzztest("xxxFuzzTest") {	#定义测试套名称CalculatorFuzzTest
  module_out_path = module_output_path

  include_dirs = [
  ]
  cflags = ["-g","-O0","-Wno-unused-variable","-fno-omit-frame-pointer"]
  sources = [
    "xxx_fuzzer.cpp",
  ]
}

[group]引用测试套,例如:

group("fuzztest") {
  testonly = true
  deps = []
  deps += [
    # deps file
    ":xxxFuzzTest",	#引用测试套
  ]
}

Fuzz配置编写

project.xml为DTFuzz参数配置文件,提供基于libFuzzer参数的动态配置,更多参数配置可参考:

https://llvm.org/docs/LibFuzzer.html#options
<!-- maximum length of a test input -->
<max_len>1000</max_len>
<!-- maximum total time in seconds to run the DTFuzz -->
<max_total_time>300</max_total_time>
<!-- memory usage limit in Mb -->
<rss_limit_mb>4096</rss_limit_mb>

用例编写中常见的强制转换

int32_t xxx= *(reinterpret_cast<const int32_t*>(data));

bool xxx= *(reinterpret_cast<const bool*>(data));

std::string xxx(reinterpret_cast<const char*>(data), size);

Fuzz用例编译

添加Fuzz用例编译到模块的test_list中:

在需要DTFuzz测试的对应模块bundle.json中添加Fuzz用例路径,如在bundle.json添加:

"tests": [
  "//foundation/xxx/xxx/test/unittest:unittest",
  "//foundation/xxx/xxx/test/fuzztest:fuzztest", #添加DTFuzz用例路径
]

在用例路径下的BUILD.gn添加group,如examples/calculator/test的BUILD.gn

group("fuzztest") {
  testonly = true
  deps = []
  
  deps += [ "fuzztest/xxx_fuzzer:fuzztest" ]
}

编译命令:

./build.sh --product-name rk3568 --export-para PYCACHE_ENABLE:true --ccache --build-target xxx_test

上32位,下64位;

./build.sh --product-name rk3568 --ccache --target-cpu arm64 --build-target xxx_test

#单独生成group的测试用例

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

生成测试用例位置:

root@ubuntu:/home/xxx/OpenHarmony/out/rk3568/tests/fuzztest/xxx/xxx#

windows下测试用例位置:

D:\file_work\22.6.25(FuzzTest)\tests\fuzztest\xxx\xxx

添加路径:D:\file_work\22.6.25(FuzzTest)\developertest\config下的user_config.xml文件

<test_cases>
  <dir>D:\file_work\22.6.25(FuzzTest)\tests</dir>
</test_cases>

修改D:\file_work\22.6.25(FuzzTest)\developertest\config下的user_config.xml文件(非必要)

<testcase>false</testcase>

(重要)在D:\file_work\22.6.25(FuzzTest)\tests\res目录下:

添加xxx_fuzzer(测试用例目录)
......

复制两文件到本地

/home/si/openharmony/test$  ls

将developertest和xdevice复制到D:\file_work\22.6.13(test)

#########################################


## Fuzz用例执行

执行前需要重新全量编译+烧录rk3568

全量编译+烧录操作看笔记


运行start.bat文件闪退

熟悉流程可以执行下一步操作


修改start.bat文件(非必要操作)

@echo off
set BASE_HOME_PATH=%CD%
@echo start time is:
TIME /T
cd %BASE_HOME_PATH%\src
python -m main %1
cd %BASE_HOME_PATH%
@echo finish time is:
TIME /T
@echo on


参考启动测试框架

Fuzz能力集成,在测试类型-t中新增FUZZ类型,执行Fuzz测试指令示例,其中-t为必选,-ss和-tm为可选

run -t FUZZ -ss developertest -tm calculator


| 参数 | 描述       | 说明     | 备注                     |
| ---- | ---------- | -------- | ------------------------ |
| -t   | TESTTYPE   | 测试类型 |                          |
| -ss  | SUBSYSTEM  | 子系统   | 被测试子系统             |
| -tm  | TESTMODULE | 模块     | 被测试模块,如calculator |

执行测试框架:

运行start.bat,输入3,回车(或选择rk3568回车)


执行DTFuzz命令示例:(不加单个测试用例就是全跑)

run -t FUZZ -ts CalculatorFuzzTest
run -t FUZZ


(可选)

在cmd中运行:

hdc_std shell


运行之后输入top查看测试进程运行时间:

top


## 测试结果与日志

- 通过在测试框架中执行测试指令,即可以生成测试日志和测试报告。

路径:D:\file_work\22.6.25(FuzzTest)\developertest\reports


- 测试结果

测试用例的结果会直接显示在控制台上,执行一次的测试结果根路径如下:

reports/xxxx-xx-xx-xx-xx-xx


测试用例格式化结果

result/


测试用例日志

log/plan_log_xxxx-xx-xx-xx-xx-xx.log


测试报告汇总

summary_report.html


测试报告详情

details_report.html


最新测试报告

reports/latest

 类似资料: