Fuzz4All
难得睡个好觉
Fuzz4All
fuzz.py
命令行参数
- config:配置文件路径,在config路径下
- folder:结果存储路径,在outputs路径下
- cpu:字面意思
- batch_size:字面意思
- model_name:使用的模型名称
- target:目标编译器路径
- gcc
- g++
- go
- javac
- cvc5:一个约束求解器
- qiskit:量子计算
配置文件参数
fuzzing:整个fuzz流程的配置
- target_name:测试目标路径,可由–target指定
- output_folder:结果文件夹,可由–folder指定
- num:fuzz迭代轮数
- total_time:总计fuzz时间,单位hour
- log_level:
- 1:info
- 2:trace
- 3:verbose
- otf:即时验证,在每次生成后验证output
- resume:是否是恢复模式
- evaluate:是否是评测模式
- use_hand_written_prompt:是否使用hand written prompt
- no_input_prompt:不需要输入prompt
- prompt_strategy:prompt策略
- 0:只使用trigger_to_generate_input进行生成
- 1:变异已有代码
- 2:语义等价已有代码
- 3:结合前两个生成的代码
target:目标编译器配置
language:语言
path_documentation:目标语言特性文档路径
path_example_code:目标语言特性示例代码
trigger_to_generate_input:例子:
1
"/* Please create a short program which uses new C features in a complex way */"
input_hint:例子:
1
"#include <stdlib.h>"
path_hand_written_prompt:一些写好的prompt
target_string:需要测试的目标名称
llm:模型配置
- temperature:模型的temperature(选择时的冒险程度或稳定程度)
- batch_size:字面意思,可用–batch_size指定
- device:字面意思,可用–cpu指定为cpu
- model_name:模型名,可用–model_name指定
- max_length:output的最大长度
fuzz loop主要流程
生成初始prompt
temperature=0,gpt生成greedy_prompt,config:
1
2
3
4
5
6
7
8
9config = {
"model": "gpt-3.5-turbo",
"max_token": 500,
"temperature": 0.0, # risk
"message": [
{"role": "system", "content": self.AP_SYSTEM_MESSAGE},
{"role": "user", "content": message + '\n' + self.AP_INSTRUCTION} # message是文档
]
}验证打分
重复三次生成:
- temperature=1,gpt生成prompt,config同上
- 验证打分
选择分数最高的prompt作为initial_prompt
进入loop:
- generate
- 选择变异策略,更新prompt
- 选择最后一个合法的output作为new_code
- 三种变异策略:
- new_code+separator
- 变异new_code
- 语法等价new_code
- 结合new_code和prev_example
cli
–config加载配置文件
main_with_config
解析配置文件
调用make_target_with_config创建Target实例
如果不是evaluate模式,则开始fuzz
- 如果不是resume模式则新建工作文件夹
1
2
3
4
5
6
7
8fuzz(
target=target,
number_of_iterations=fuzzing["num"],
total_time=fuzzing["total_time"],
output_folder=folder,
resume=fuzzing["resume"],
otf=fuzzing["otf"],
)如果是evaluate模式则调用evaluate_all进行evaluate
1
evaluate_all(target)
就是分别验证(编译或运行)每个output
fuzz
initialize target
1
target.initialize()
initialize见target/target.py
进入fuzz loop,迭代次数number_of_iterations
使用self.prompt生成outputs
对于每个output:
- 写入文件
- 如果设置了otf,则:
- 调用validate_individual验证output(编译/运行)
- 调用parse_validation_message解析验证结果信息,记录进log
调用update更新target
update见target/target.py
make_model.py
make_model
kwargs_for_model:参数
- model_name
- eos
- device
- max_length
创建StarCoder实例
1
model_obj = StarCoder(**kwargs_for_model)
返回model_obj
输出:
1 |
|
class StarCoder
__init__
model_name,device,eos,max_length
device
tokenizer
model
eos:eos + EOF_STRINGS
1
EOF_STRINGS = ["<|endoftext|>", "###"]
prefix_token:
1
<fim_prefix>
suffix_token:
1
<fim_suffix><fim_middle>
skip_special_tokens:False
generate
prompt生成代码
inference_mode关闭一堆东西提高速度
1
@torch.inference_mode()
给prompt添加前后缀
用tokenizer获取input_tokens
EndOfFunctionCriteria用于实时检测生成是否已结束(出现eos),是则记录去除eos后的输出长度
1
2
3
4
5
6
7
8
9scores = StoppingCriteriaList(
[
EndOfFunctionCriteria(
start_length=len(input_tokens[0]),
eos=self.eos,
tokenizer=self.tokenizer,
)
]
)生成
1
2
3
4
5
6
7
8
9
10
11
12
13raw_outputs = self.model.generate(
input_tokens,
max_length=min(self.max_length, len(input_tokens[0]) + max_length),
do_sample=True,
top_p=1.0,
temperature=max(temperature, 1e-2),
num_return_sequences=batch_size,
stopping_criteria=scores,
output_scores=True,
return_dict_in_generate=True,
repetition_penalty=1.0,
pad_token_id=self.tokenizer.eos_token_id,
)- do_sample:是否在生成文本时使用采样策略,如果设置为False,则使用贪心策略进行解码(总是选择概率最高的下一个token)
- top_p:保留累计概率达到p的最小集合,然后从这个集合中进行选择
- num_return_sequences:设置生成几个文本
- repetition_penalty:防止文本重复
- stopping_criteria:停止条件
- output_scores:让模型同时返回输出和对应的分数
- return_dict_in_generate:方法会返回一个字典,其中包含生成的文本和其他相关信息,如attention masks等
去除每个输出的prompt部分
去除每个输出的eos
make_target.py
make_target_with_config
target_compat_dict:一个压缩过的config_dict
- language
- folder:output_folder
- bs:batch_size
- temperature
- device
- model_name
- max_length
- use_hw:use_hand_written_prompt
- no_input_prompt
- prompt_strategy
- level:log_level
- template:fuzzing_with_config_file
- config_dict:完整的config_dict,解析自配置文件
- target_name
根据语言创建对应Target实例,并返回Target实例:
- cpp:CPPTarget
- c:CTarget
- qiskit:QiskitTarget
- smt2:SMTTarget
- go:GOTarget
- java:JAVATarget
Target见target/target.py,子类见子文件夹
target
target.py
class Target
参数是make_target_with_config中的target_compat_dict
__init__
language,timeout,folder,
language
timeout
folder
CURRENT_TIME:获取现在时间
batch_size
temperature
max_length
device
model_name
model:None
g_logger:结果目录下的log_generation.txt文件,格式:
1
f"[{level.name}] {msg}"
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18[VERBOSE] #include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
int main(void) {
unsigned i = 1l;
#ifdef UINTPTR_MAX
printf("Unsigned integers are %zu bytes.\n", sizeof(i));
#else
printf("Unsigned integers are %zd bytes.\n", sizeof(i)*CHAR_BIT);
#endif
i++;
printf("unsigned i is now %zd bytes long.\n", sizeof(i))*CHAR_BIT;
printf("unsigned i is now %" PRIu64 "\n", i);
return 0;
}v_logger:结果目录下的log_validation.txt文件,例子:
1
2
3
4
5
6
7
8
9
10
11
12[TRACE] Validating outputs/full_run/gcc/0.fuzz ...
[VERBOSE] outputs/full_run/gcc/0.fuzz failed validation with error message: outputs/full_run/gcc/0.fuzz: In function main:
outputs/full_run/gcc/0.fuzz:15:62: error: CHAR_BIT undeclared (first use in this function)
15 | printf("unsigned i is now %zd bytes long.\n", sizeof(i))*CHAR_BIT;
| ^~~~~~~~
outputs/full_run/gcc/0.fuzz:5:1: note: CHAR_BIT is defined in header <limits.h>; did you forget to #include <limits.h>?
4 | #include <inttypes.h>
+++ |+#include <limits.h>
5 |
outputs/full_run/gcc/0.fuzz:15:62: note: each undeclared identifier is reported only once for each function it appears in
15 | printf("unsigned i is now %zd bytes long.\n", sizeof(i))*CHAR_BIT;
| ^~~~~~~~m_logger:结果目录下的log.txt文件,例子:
1
2
3
4
5
6
7
8
9
10[INFO] Loading model ...
[INFO] Initializing ... this may take a while ...
[INFO] Loading model ...
[INFO] Model Loaded
[INFO] Use auto-prompting prompt ...
[INFO] Initializing ... this may take a while ...
[INFO] Loading model ...
[INFO] Model Loaded
[INFO] Use auto-prompting prompt ...
[INFO] DoneSYSTEM_MESSAGE:子类设置
AP_SYSTEM_MESSAGE:系统提示prompt
1
"You are an auto-prompting tool"
AP_INSTRUCTION:生成命令prompt
1
2"Please summarize the above documentation in a concise manner to describe the usage and "
"functionality of the target "hw:use_hand_written_prompt
no_input_prompt
prompt_used:子类设置
prompt:None
initial_prompt:None
prev_example:None
se_prompt:语法等价替换变异策略的prompt
1
2
3
4self.se_prompt = self.wrap_in_comment(
"Please create a semantically equivalent program to the previous "
"generation"
)m_prompt:变异之前的代码变异策略的prompt
1
2
3self.m_prompt = self.wrap_in_comment(
"Please create a mutated program that modifies the previous generation"
)c_prompt:结合之前两段代码变异策略的prompt
1
2
3self.c_prompt = self.wrap_in_comment(
"Please combine the two previous programs into a single program"
)p_strategy:prompt_strategy
special_eos:None
target_name:target
_create_prompt_from_config
从config获取各种prompt
target:配置文件的target,提供
- path_documentation
- path_example_code
- trigger_to_generate_input
- input_hint
- path_hand_written_prompt
- target_string
trigger_to_generate_input:见配置文件
documentation:读取自path_documentation
example_code:读取自path_example_code
input_hint:见配置文件
hand_written_prompt:读取自path_hand_written_prompt
target_string:见配置文件
dict_compat:
1
2
3
4
5
6
7
8dict_compat = {
"docstring": documentation,
"example_code": example_code,
"separator": trigger_to_generate_input,
"begin": input_hint,
"hw_prompt": hand_written_prompt,
"target_api": target_string,
}
返回dict_compat
validate_prompt
给prompt打分
调用generate使用prompt生成
1
2
3
4
5
6fos = self.model.generate(
prompt,
batch_size=self.batch_size,
temperature=self.temperature,
max_length=self.max_length,
)generate见model.py
对于每个output:
补充begin,为了编译或运行之后会去掉
将output写回文件
调用validate_individual验证输出,就是编译或运行
如果output:
- 验证为SAFE
- 包含目标api,filter清除begin
- clean_code清除注释和空行后不在set里
则放入set,score+1
返回score
auto_prompt
生成初始prompt
工作路径下创建prompt文件夹
如果已经有prompt,则直接使用
如果设置了no_input_prompt,则直接使用prompt_used中的separator和begin作为best_prompt
如果设置了use_hand_written_prompt,则使用hand written prompt
否则自动生成prompt
调用create_config生成config,temperature为0
1
2
3
4
5
6
7
8
9config = {
"model": "gpt-3.5-turbo",
"max_token": 500,
"temperature": 0.0, # risk
"message": [
{"role": "system", "content": self.AP_SYSTEM_MESSAGE},
{"role": "user", "content": message + '\n' + self.AP_INSTRUCTION} # message是文档
]
}调用request_engine获取gpt的response
1
response = request_engine(config)
选取第一个message作为greedy_prompt
best_prompt初始化为greedy_prompt,调用validate_prompt给greedy_prompt打分,score表示有效输出的个数,具体为包含目标api的、不重复的output数量
重复三次request_engine(temperature为1)和validate_prompt选取分数最高的prompt作为best_prompt
initialize
target初始化,加载模型,初始化prompt
初始化一个eos列表,这些prompt根据需要作为语句结尾
1
2
3
4
5
6
7[
trigger_to_generate_input,
"<eom>", # for codegen2
se_prompt,
m_prompt,
c_prompt
]添加special_eos,go和smt有这个
调用make_model加载模型
1
2
3
4
5
6self.model = make_model(
eos=eos,
model_name=model_name,
device=self.device,
max_length=self.max_length,
)make_model见model.py
调用auto_prompt获取initial_prompt
1
2
3
4
5
6self.initial_prompt = self.auto_prompt(
message=self.prompt_used["docstring"],
hw_prompt=self.prompt_used["hw_prompt"] if self.hw else None,
hw=self.hw,
no_input_prompt=self.no_input_prompt,
)参数:
- message:文档
- hw_prompt:一些写好的prompt
- hw:是否使用hand written prompt
- no_input_prompt:不需要输入prompt
update_strategy
选择一个变异策略,生成新的prompt
0:new_code+trigger_to_generate_input
1
f"\n{new_code}\n{self.prompt_used['separator']}\n"
1:变异new_code
1
f"\n{new_code}\n{self.m_prompt}\n"
2:语法等价new_code
1
f"\n{new_code}\n{self.se_prompt}\n"
3:结合前两个生成的代码:
- prev_example
- trigger_to_generate_input
- input_hint
- new_code
- combine prompt
1
f"\n{self.prev_example}\n{self.prompt_used['separator']}\n{self.prompt_used['begin']}\n{new_code}\n{self.c_prompt}\n"
update
每轮fuzz loop后更新target
选择最后一个filter合法、clean_code后不等于prev_example的code
更新prompt为:
1
2
3
4
5
6self.prompt = (
self.initial_prompt
+ self.update_strategy(new_code)
+ self.prompt_used["begin"]
+ "\n"
)更新prev_example为code
C.py
class CTarget
__init__
SYSTEM_MESSAGE:
1
"You are a C Fuzzer"
config_dict
prompt_used:调用_create_prompt_from_config生成,包括
- docstring:文档
- example_code:示例代码
- separator:trigger_to_generate_input,见配置文件
- begin:input_hint,见配置文件
- hw_prompt:写好的prompt
- target_api:测试目标
_create_prompt_from_config见target/target.py
wrap_prompt
prompt打包
1 |
|
示例:
1 |
|