[关闭]
@yinnner 2018-12-08T05:27:00.000000Z 字数 2975 阅读 1744

用于代码缺陷检测的数据集生成

论文地址:Towards security defect prediction with AI

代码仓库地址:sa-bAbI

数据集sa-bAbi的生成

核心文件:

  1. sa_babi/
  2. .
  3. ├── generate.py # 主要生成代码的文件
  4. ├── sa_tag.py # 每行代码性质标签
  5. └── templates.py # 生成不同模块(控制流、函数体等)的模版

如果要添加漏洞种类,则则需要往sa_tag.py中添加新的行标签,往templates.py中添加新的模块模版。

generate.py重要函数逻辑如下:

main()函数逻辑

  1. 获得参数和路径并检查
  2. 设置种子
  3. 得到生成器数组generators(含有各种例子生成器的数组)
    • 如果设置为linear_only表示代码顺序执行,不包含控制流,生成器只有一种。
  4. 开始循环生成代码例子
    1. 利用取模操作获得当前使用的生成器
    2. 传递参数调用对应的生成器生成代码和对应标签
    3. 利用哈希生成文件名,发生碰撞则重新生成代码
    4. 写文件元数据到元数据数组
    5. 将生成代码和标签写入c文件
  5. 将元数据数组(该数据集的所有元数据)写入json文件。

各生成器函数逻辑

有以下几种生成器,对应相应的函数:

buffe write 格式:"$buf_var[$idx_var] = '$char';"

fv含义:free variable

函数名/生成器 作用
gen_cond_example idx_var经过while循环模块得到
gen_for_example $idx_var经过for循环模块得到
gen_fv_cond_example 有一个自由变量,经过if条件判断模块
gen_fv_while_example 有一个自由变量,经过while循环模块
gen_fv_for_example 有一个自由变量,for循环模块
gen_tautonly_linear_example 不经过控制流直接进行不安全的buffer write

以上生成器逻辑几乎相同,只是需要的变量和判断safe的条件不一样。逻辑如下:

  1. 得到所有匿名变量——调用_get_anon_vars()生成得到。
  2. 选前3个变量作为关键变量,其余为无关紧要的变量dummy_vars,只用来传递数值,实际不起什么作用。
  3. 通过random随机生成关键变量需要用到的关键数值。
  4. 得到buffer write的字符——调用_get_char()生成得到。
  5. substitutions字典将其封装好。
  6. 从模版中得到模块主要代码行templates.xxx_MAIN_LINES
  7. 用关键数值判定是否安全,布尔变量safe用来指示。
  8. 从模版中得到模块的声明初始化变量代码行templates.xxx_DEC_INIT_PAIRS
  9. 传入以上参数,调用_assemble_general_example组装模块生成代码。

gen_tautonly_linear_example函数由于不经过控制流,直接进行buffer write,因此所有变量都是dummy_varssubstitutionsmain_linesdec_init_pairs均为空。

如果要添加漏洞种类,我觉得可以按照以上函数的模式写gen_xxx_{Vulnerability Name}_example7个对应函数,具体是否要写那么多个要看漏洞的性质,main函数可能只需要少量改动。

_assemble_general_example()

组装模块函数逻辑:

  1. 判定是否包含条件buffer write,包含则给main_lines加一句templates.BUFWRITE_LINES
  2. 调用_get_lines得到所有代码行。(这个函数及相应调用函数需要修改。)
  3. 调用_get_tags得到所有代码行标签。
  4. 调用_get_instance_str得到最终c语言代码文本。

_get_lines()

获得所有代码行,包含声明初始化、主体内容、dummy变量

(只用来传递数值,实际不起什么作用)的使用。函数逻辑:

  1. 调用_get_setup_lines获得声明初始化代码行。
  2. setup_lines + main_lines构成所有代码行。
  3. 为所有代码行打上body标签,如果包含条件buffer write(include_cond_bufwrite == True),则为最后一个代码行(即为buffer write代码)打上Tag.BUFWRITE_COND_SAFETag.BUFWRITE_COND_UNSAFE(通过safe判断)。
  4. 在指定最大最小值范围随机生成dummy变量的个数。
  5. 调用_insert_dummies为现有代码行添加dummy变量相关的代码行。

_insert_dummies()

插入所有dummy变量的声明和赋值语句。函数逻辑如下:

  1. setup_lines + main_lines构成所有代码行。
  2. 获得控制流代码行的开始和结束索引。
  3. 循环num_dummies次,调用_insert_referential_dummy依次插入每一个dummy变量的相关代码行。

_insert_referential_dummy()

插入指定dummy变量的声明、初始化和buffer write语句。这里面出现的buffer write不经过控制流,因此标签为BUFWRITE_TAUT_SAFE 或 BUFWRITE_TAUT_UNSAFE。

函数逻辑如下:

  1. 判断dummy变量个数,小于2报错(一次需要用到两个dummy变量)。
  2. 根据是否需要安全赋值,设置dummy数组长度dum_len和buffer write需要用到的下标dum_idx
  3. 从dummy_vars中取出两个变量用作:buffer write的数组变量——dum_buf_var;指示buffer write位置的下标——dum_int_var
  4. 按照格式利用上述的4个参数设置声明、赋值、buffer write代码行。
  5. 组织声明初始化代码行顺序。
  6. 决定是否声明初始化代码行开始和结束位置。
  7. 在开始和结束范围内随机生成声明初始化代码行位置索引。
  8. 在声明初始化代码行后的位置随机生成buffer write代码行位置。
  9. 根据上述索引修正更新控制流开始和结束位置。
  10. 将上述代码行插入原来的代码行lines中。
  11. 根据dum_idxdum_len的大小关系判断buffer write是否安全。
  12. 将上述代码行对应标签插入原来的标签body_tags中。

_test()

测试每个生成器生成代码。

这个函数大部分不需要修改,只需要改从745-757行测试标签种类的代码。

不需要修改的函数

函数名 作用
_get_char() 获得一个字符
_get_anon_vars() 获得MAX_NUM_VARS个变量并打乱
_get_tags() 获得完整的标签,即加上函数主体外的其他标签(#include... int main() {return 0;})
_get_instance_str() 替换模版中的文本并获得最终c语言代码文本。
_get_setup_lines() 获得打乱顺序的声明初始化变量代码行
_get_args() 设置命令行参数格式并获得命令行参数(可能会修改)
_get_full_template() 似乎这个文件里面没有使用到
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注