一种新型分析信息流的方法 技术领域 本发明是属于信息安全技术领域, 涉及一种信息流分析技术应用于系统进行隐通 道分析的方案, 具体地说涉及一种基于系统源代码搜索隐通道的信息流分析方法。
背景技术 自隐通道问题提出以来, 各国的信息安全专家, 以及计算机、 数学、 通讯等方面的 相关学者通过广泛地研究发现, 隐通道在信息安全方面特别是信息的机密性泄露方面具有 一定的危害性。搜索出系统中存在的隐通道是进行隐通道分析工作的前提和基础。在众多 隐通道搜索方法中, 信息流分析法较为引人关注。
信息流分析法是最早提出的隐通道搜索方法, 分为语法信息流方法和语义信息流 方法。Denning 的信息流格模型是语法信息流方法的典型代表。此方法的核心思想是, 任 何对系统安全策略的违反 ( 包含隐通道 ), 都将体现为对 “格 (Lattice)” 定义的破坏。通 常, 语法信息流分析方法的分析步骤是 : (1) 将信息流附加在每条语句之后。 以赋值语句 a : = b 为例, 产生由 b 到 a 的信息流, 用 a ← b 表示。(2) 定义安全信息流策略, 如果有信息 流 a ← b, 则 a 的安全级必须支配 b 的安全级。(3) 将流策略应用于形式化顶级描述或源代 码, 生成信息流公式, 例如 a : = b 语句的流公式为 SL(a) ≥ SL(b), 其中 SL(a) 和 SL(b) 分 别表示变量 a 和 b 的安全级。 (4) 证明信息流公式的正确性, 如果无法证明某个流公式的正 确性, 则需要进一步对语句进行语义分析。该方法的优点在于不会漏掉可能产生隐通道的 非法信息流, 但同时也产生大量的伪非法流, 需要通过手工的语义分析消除伪非法流。
此后, Tsai 等人对信息流分析方法作了很大的改进, 增加了语义分析, 提出了一种 基于语义信息流分析的隐通道搜索方法, 即一种语义信息流方法。此方法的核心思想是 : (1) 分析编程语言的语义、 代码和内核中使用的数据结构, 发现变量的可见性和可修改性 ; (2) 解决变量的别名问题, 确定变量的间接可修改性 ; (3) 对源代码进行信息流分析, 确定 变量的间接可见性。改进的语义信息流方法可以发现大量伪非法流。
信息流分析法既可以应用于系统形式化顶级描述, 也可以应用于系统源代码进行 隐通道分析。对于一些形式化语言, 已经有了成功的自动信息流分析工具, 能够对系统的 形式化顶级描述作比较完全的信息流分析。但形式化描述与具体实现的系统源代码之间 总是有差别的, 而目前比较有影响的应用于系统源代码的信息流自动分析工具仅见 He 与 Gligor 研制的工具。
目前基于系统形式化顶级描述分析信息流的隐通道搜索方法缺陷
为简化工作量、 得到较高的工作效率, 目前主要是基于系统顶级描述进行系统中 的隐通道搜索工作。 因为与系统源代码相比较, 系统顶级描述简单易懂, 对分析人员的要求 相对较低, 从而省去很多繁琐的工作。然而, 尽管这样可以得到较高的工作效率, 但由于系 统顶级描述并没有真实地体现系统实现的细节, 所以搜索结果的精度并不高, 会出现漏报 和错报的情况。
目前基于系统源代码分析信息流的隐通道搜索方法缺陷
由于源代码复杂难懂, 直接针对系统源代码分析信息流的工作量很大, 目前这类 搜索方法缺乏行之有效的自动化工具, 需要辅之以手工操作分析源代码中的信息流, 对分 析人员的要求相当高, 显然对于较大规模的系统来说, 工作效率低, 容易出错。He 与 Gligor 研制的自动化工具应用了系统强制安全模型在源代码中的解释, 不能区分伪非法流与真实 非法流。 发明内容 本发明的目的是解决基于系统源代码搜索隐通道的问题。基于程序设计语言语 义, 设计一套系统源代码中信息流的描述方法, 结合共享资源矩阵法, 提出一种基于系统源 代码搜索隐通道的信息流分析方法。
本发明方法利用二叉树结构来描述系统源代码中的信息流, 通过遍历树将这些信 息存放在直观、 易于理解的信息流向图中, 为搜索隐通道提供信息流分析结果, 再以此作为 输入, 构造共享资源矩阵, 分析系统中的隐通道。
本发明的技术方案是 : 一种基于系统源代码搜索隐通道的信息流分析方法, 包括 下列步骤 :
(1) 扫描系统源代码
借助程序设计语言编译系统中的词法分析程序, 扫描系统源代码, 分别识别出源 代码中的函数和函数中的语句、 变量 ; 根据扫描程序识别出的函数以及函数调用语句, 确定 函数间的调用关系, 给出每个函数的函数依赖集。
(2) 构造信息流树
根据扫描程序识别出的能产生信息流的语句和变量, 作为信息流分析的输入, 对 语句中的信息流进行分析, 采用一种二叉树结构来存放语句中的信息流信息, 称之为 “信息 流树” 。信息流树的构造方法如下 :
针对能产生信息流的各类语句, 依据语句信息流规则, 分别给出各类语句树段的 构造规则, 并且定义了由语句树段生成函数信息流树的规则 ;
当扫描程序识别出某类信息流语句时, 根据此类语句的信息流树构造规则, 先生 成语句树段, 用来记录此语句中的信息流 ;
再根据函数信息流树的构造规则, 由函数中各语句的信息流树生成函数信息流 树, 从而获得各个函数中的信息流。
(3) 信息流树剪枝
通过分析函数内部信息流的特点, 结合信息流的传递性, 给出信息流树剪枝的依 据;
利用剪枝依据, 将函数中与隐通道分析无关的信息流树枝剪掉, 得到只记录函数 中与共享变量相关的信息流信息。
(4) 生成信息流向图
根据遍历算法, 对函数信息流树进行遍历, 生成函数的信息流向图, 图中记录函数 中共享变量的可见性和可修改性信息, 即信息流分析的结果。
(5) 生成共享资源矩阵并搜索隐通道
根据函数的信息流向图, 以函数依赖集为单位, 获得依赖集中函数间的共享变量
可见性和可修改性信息, 并生成用于共享资源矩阵隐通道搜索方法进行隐通道分析的矩阵 结构 ; 然后再以共享资源矩阵作为输入, 搜索隐通道, 输出系统中存在的隐通道序列。
为说明信息流树结构, 这里介绍几个和信息流树相关的定义。
①结点 : 信息流树中的最小单位, 对应着函数各语句中的语句关键字 ( 如 if, while 等 )、 运算符 ( 如 “=” ) 及变量。为能描述出所有的信息流, 我们定义了三种结点 : “stmt” 结点为语句结点 ; “var” 结点为变量结点, 记录信息流中源变量和目标变量的信息 ( 如变量名, 变量类型等信息 ) ; “nullstmt” 结点没有任何意义, 仅用于嵌套控制语句中控 制语句紧邻出现的情况, 用此结点作为一个过渡结点。
②语句树段 : 结点按照一定的规则所构成的用来描述一条语句中信息流的二叉 树, 称为语句树段。 对函数中每一条语句, 都要构造其语句树段, 用来描述语句中的信息流。
③信息流树 : 也是一种二叉树, 由若干个语句树段连接而成, 用来描述一个函数中 的信息流。信息流树对应着函数, 而构成信息流树的这些语句树段则分别对应着函数中的 各条语句。
对于上述系统源代码扫描步骤, 进一步说明如下 :
为实现一个基于系统源代码的隐通道搜索工作的自动化, 首先要解决的是自动扫 描并分析系统源代码, 根据扫描结果构造出用于信息流分析的函数信息流树, 并且确定函 数间的相互调用关系, 即函数依赖集。 为达到这一目的, 考虑到一个语言的编译程序可以对 源代码进行扫描并分析, 借助高级语言编译系统中的词法分析程序, 来完成对系统源代码 的扫描。 词法分析器以源程序作为输入, 将其转化为记号输出。记号是指从源程序读入的 一组字符串 ( 如变量名、 关键字、 常数 ), 通过词法分析器转化输出的形式, 而读入的这一组 字符串就称为记号的一个词素。程序设计语言中常把标识符 ( 包括变量名、 数组名、 函数名 等等 )、 关键字、 操作符、 常量、 文字串和标点符号作为记号处理。一个记号往往会对应多个 词素, 例如, 高级语言中常用 id 作为标识符的记号, 如 pi、 D2 这两个不同的变量名, 在以记 号形式输出时都表示为 id, 这样不足以区分不同的标识符。 因此, 词法分析器必须为这个记 号提供附加的信息, 称之为记号的属性, 与记号构成一个二元式输出。
上述信息流树构造步骤进一步包括如下步骤 :
首先分类定义程序设计语言的语句信息流规则 ( 以 C 语言为例 ), 然后依据语句信 息流规则, 给出各类语句树段的构造方法 ; 在此基础上, 构造函数信息流树。
(1) 所述语句信息流规则
在 Tsai 和 Gligor 给出的简单信息流规则的基础上, 针对高级语言中语句各自的 特点, 将语句分为赋值语句、 函数返回值语句、 函数调用语句、 控制语句和嵌套控制语句五 类, 分别给出它们的信息流规则。
①赋值语句信息流规则
规则 1.1va = vb ; 则有信息流 : vb- > va ;
规则 1.2va-- 或 va++ ; 则有信息流 : va- > va ;
规则 1.3va = vb ; 且 va, vb 均为指针, 则有信息流 : vb- > va, va- > vb ;
规则 1.4va = &vb ; 且 va 为指针, 则有信息流 : vb- > va, va- > vb ;
规则 1.5va = vb op...op vn ; 其中 op 代表运算符, 则有信息流 : vb- > va, ...,
vn- > va。
②函数返回值语句信息流规则
规则 2.1return(va) ; 则有信息流 : va- > *, 其中, * 代表语句所在的函数 ;
规则 2.2return(va op...op vn) ; 则有信息流 : va- > *, ..., vn- > *。
③函数调用语句信息流规则
规则 3.1va = F(x) ; 其中 F(x) 代表函数, 则有信息流 : x- > va ;
规则 3.2F(x) ; 则有 x- > *, 其中 * 代表语句所在的函数 ;
规则 3.3va = F(x1, ..., xn) ; 则有信息流 : x1- > va, ..., xn- > va ;
规则 3.4F(x1, ..., xn) ; 则有 x1- > *, ..., xn- > *。
④控制语句信息流规则
规则 4.1 对于下面四条语句 :
规则 4.2if/while(va op_com K){vb = m1 ; ... ; vn = mn ; }; 则有信息流 : va- > vb, ..., va- > vn ;
规 则 4.3switch(va)(case : vb = m1 ; ... ; default : vn = mn ; ); 则有信息流: va- > vb, ..., va- > vn ;
规则 4.4if/whi le(va op_com K)return ; 则有信息流 : va- > * ;
规则 4.5switch(va)(case : return ; ... ; default : return ; ); 则有信息流 : va- > *;
规则 4.6if/while(va op_com K){vb = m1 ; ... ; return ; }; 则有信息流 : va- > vb, ..., va- > * ;
规则 4.7switch(va)(case : vb = m ; ...default : return ; ); 则有信息流 : va- > vb, ..., va- > * ;
规则 4.8if/while(F(x) op_com K)va = m ; 则有信息流 : x- > va ;
规则 4.9if/while(F(x)op_com K)return ; 则有信息流 : x- > * ;
规则 4.10if/while(F(x)op_com K){va = m1 ; ...vn = mn ; }; 则有信息流 : x- > va, ..., x- > vn ;
规则 4.11if/while(F(x)op_com K){va = m1 ; ...return ; }; 则有信息流 : x- > va, ..., x- > * ;
规则 4.12if/while(F(x1, ..., xn)op_com K){va = m1 ; ...} ; 则有信息流 : x1- > va, x1- > ..., ..., xn- > va, xn- > ... ;
规则 4.13if(va op_com K){vb = m ; ...}else{vc = n ; ...} ; 则有信息流 : va- > vb, ... ; va- > vc... ;
规 则 4.14if/while((va op_com K1)op_log...op_log(vn op_com Kn)){vm = m; ...} ; 则有信息流 : va- > vm, va- > ..., ..., vn- > vm, vn- > ...。
规则 4.15va = (vb op...vn) ? vc : vd ; 则有信息流 : vb- > va, ..., vn- > va。
⑤嵌套控制语句信息流规则
规则 5.1
其中 controlstmt 代表 if、 while、 switch( 若为 switch, 则相应的改为分支语句 的结构形式 ), op 代表比较运算符或逻辑运算符, 则有信息流 : va- > ... ①, va- > ... ②, va- > ... ③, ..., vb- > ... ②, ... ; 其中①、 ②、 ③是为区分三个 “...” 部分。
规则 5.2
则有信息流 : va- > ... ①, va- > ... ②, ..., vb- > ... ①, ...。 规则 5.3则有信息流 : va- > ... ①, va- > ... ②, va- > ... ③, ...。
(2) 所述语句树段构造规则
在构造语句树段时, 遵循一个大的原则 : 语句信息流的源变量信息始终记录在左 孩子变量结点中, 而语句信息流的目标变量信息始终记录在右孩子变量结点中。基于这一 原则给出语句树段的构造规则。其中, 相对于嵌套控制语句, 赋值语句、 函数返回值语句、 函数调用语句和控制语句的语句树段构造过程比较简单, 所以将这四类语句统称为简单语 句。下面首先讨论简单语句树段的构造规则, 再讨论嵌套控制语句树段的构造规则。
①简单语句树段构造规则
a) 对每一个语句, 生成一个语句结点作为根结点 ;
b) 对语句信息流中的源变量, 若源变量只有一个, 则生成一个记录该源变量信息 的变量结点, 作为根结点的左孩子 ; 若源变量有多个, 则分别生成记录不同源变量信息的变 量结点, 生成的过程中将后一源变量结点作为前一源变量结点的左孩子, 构成一棵只有左 分支的二叉树, 并把此树作为根结点的左子树 ;
c) 对语句信息流中的目标变量, 若目标变量只有一个, 则生成一个记录该目标变 量信息的变量结点, 作为根结点的右孩子 ; 若目标变量有多个, 则分别生成记录不同目标变 量信息的变量结点, 生成的过程中将后一目标变量结点作为前一目标变量结点的右孩子, 构成一棵只有右分支的二叉树, 并把此树作为根结点的右子树。
②嵌套控制语句树段构造规则
a) 对于最外层的控制语句, 先生成一个语句结点作为根结点 ; 再生成一个或多个 变量结点, 记录控制语句中判断变量或循环控制变量 ( 源变量 ) 的信息, 生成的过程中将后 一源变量结点作为前一源变量结点的左孩子, 构成一棵只有左分支的二叉树, 并把此树作 为根结点的左子树。
b) 对于控制语句语句体内的赋值表达式、 自增 / 自减表达式、 函数调用语句或函 数返回值表达式, 生成记录表达式中目标变量信息的变量结点, 若控制语句根结点没有右 孩子, 则将此变量结点作为其右孩子 ; 否则, 将其作为在它之前生成的结点的右孩子。
c) 对于控制语句语句体内的某一嵌套控制语句, 若其与上一层控制语句不紧邻 ( 如规则 5.1), 则先将该嵌套控制语句作为一独立的控制语句, 按照策略 a) 至 c) 生成其语 句树段, 然后将此语句树段作为在它之前生成的目标变量结点的左子树 ; 若其与上一层控
制语句紧邻 ( 如规则 5.2), 则先生成一个 “nullstmt” 结点, 作为上一层控制语句的右子树 结点, 然后按照策略 a) 至 c) 生成该嵌套控制语句的信息流树, 再将其作为 “nullstmt” 结 点的左子树。
d) 若某一控制语句的循环控制条件为空或为一常量, 则其语句体必然有一个嵌套 的控制语句中有跳出循环的 break 语句。对于这种情况, 将该嵌套控制语句的源变量结点 作为外层控制语句的源变量结点。
(3) 所述信息流树构造规则
有语句树段构造规则作为基础, 信息流树的生成很简单 : 按照函数中语句的执行 顺序, 将后一语句的树段作为前一语句树段最末目标变量结点的右子树。函数中所有语句 树段按此规则生成的二叉树即为函数的信息流树。
对于信息流树剪枝步骤进一步说明如下 :
上述信息流树剪枝主要是为了将函数信息流树中记录函数内部信息流的树枝剪 掉。函数内部信息流指的是和函数中局部变量相关的信息流, 这些信息对隐通道分析来 说没有意义, 因此为方便接下来的隐通道搜索工作, 在信息流树的构造过程中, 对其进行剪 枝。通过分析函数内部信息流的特点, 结合信息流的传递性, 给出了信息流树剪枝的依据。 剪枝的目的就是使得函数信息流树中只反映和隐通道分析相关的共享变量的信 息流动情况。函数间可以共享的变量即为全局变量, 因此, 在对信息流树进行剪枝时, 只保 留树中和全局变量相关的信息流即可。
信息流树剪枝是在函数信息流树生成的过程中同时进行的, 这样可以大大地节省 时间和存储空间, 得到更高的效率。
剪枝算法包括以下步骤 :
(1) 对函数中的语句, 构造语句树段, 若语句为简单语句, 则按 (2) 处理 ; 若语句为 嵌套控制语句, 则按 (3) 处理 ;
(2) 对函数中简单语句树段进行遍历, 遍历的过程中查看是否需要剪枝 : 遍历源 变量结点时, 按 (4) 处理 ; 遍历目标变量结点时, 按 (5) 处理 ; 遍历非变量结点时, 无需任何 处理 ;
(3) 函数中嵌套控制语句的信息流树进行遍历, 遍历的过程中查看是否需要剪枝 : 遍历目标变量结点时, 按 (5) 处理 ; 遍历源变量结点时, 查看以它为源变量的目标变量结 点: 若有某一目标变量结点与其记录的变量相同, 则无需任何处理 ; 否则, 按 (4) 处理 ; 遍历 非变量结点时, 无需任何处理 ;
(4) 对源变量结点, 考察已生成的函数信息流树中的每一个变量结点, 若其中某一 变量结点是它父结点的右孩子, 且与该源变量结点记录的是同一变量, 则分以下两种情况 处理 :
①记录的是局部变量, 则将这一变量结点的父结点的左子树复制, 并替换该源变 量结点 ;
②记录的是全局变量, 则将这一变量结点的父结点的左子树复制, 并做为该源变 量结点的左子树 ;
(5) 对目标变量结点, 考察已生成的函数信息流树中的每一个变量结点, 若其中 某一变量结点是它父结点的右孩子, 且与该结点记录的是同一变量, 则分以下三种情况处
理: ①这一变量结点有左子树, 则用 “nullstmt” 类型结点替换它 ;
②这一变量结点无左子树, 且它的父结点和右孩子结点均为语句结点, 则将它所 在的语句树段从树中删除 ;
③这一变量结点无左子树, 且它的父结点或右孩子结点不是语句结点, 则仅将此 变量结点从信息流树中删除 ;
(6) 将经过剪枝处理的语句树段连到函数信息流树中 ;
(7) 对函数中每一条语句, 重复以上步骤, 直到函数体结束 ;
(8) 对得到的函数信息流树考察其所有变量结点, 若某一变量结点是它父结点的 左孩子, 且结点中记录的是局部变量, 则将该变量结点从树中删除 ;
(9) 对得到的函数信息流树考察其每一个语句树段, 对简单语句树段, 按 (10) 处 理; 对嵌套控制语句树段, 按 (11) 处理 ;
(10) 对简单语句树段, 若其中某一变量结点是它父结点的右孩子, 且它记录的是 局部变量, 则分以下两种情况处理 :
①这一变量结点的父结点和右孩子结点均为语句结点, 则将此树段从信息流树中 删除 ;
②这一变量结点的父结点或右孩子结点是变量结点, 则仅将此结点从语句树段中删除 ; (11) 对嵌套控制语句树段, 若其中某一变量结点是它父结点的右孩子, 且它记录 的是局部变量, 则分以下两种情况处理 :
①这一变量结点的父亲结点和右孩子结点都不是变量结点, 则用 null 类型结点 代替此结点 ;
②这一变量结点的父亲结点或右孩子结点是变量结点, 则仅将此右子树结点从语 句树段中删除。
对于所述信息流向图生成步骤进一步说明如下 :
由于各变量间的信息流动不是单一的线性关系, 有可能构成复杂的网状, 因此采 用图结构来描述函数各变量间的信息流向情况, 称之为 “信息流向图” 。生成信息流向图是 为了提供直观的信息流分析结果。 构造出函数信息流树之后, 根据给出的遍历算法, 对函数 信息流树进行遍历, 生成函数的信息流向图, 图中记录函数中共享变量的可见性和可修改 性信息, 即信息流分析的结果。
由函数信息流树生成信息流向图的方法如下 :
(1) 信息流树线索化
为方便遍历信息流树生成信息流向图, 在构造函数信息流树和简枝的过程中, 还 要将其线索化。线索的建立过程很简单, 在构造语句树段时, 令源变量结点 ( 即左子树变量 结点 ) 的右子树指针始终指向其后生成的目标变量或 null 类型结点, 并令目标变量结点的 右子树指针也始终指向其后生成的结点。
(2) 遍历线索化的信息流树, 生成信息流向图
信息流向图的生成过程实际上就是对于树中每一个语句树段的每一个左子树变 量结点, 遍历所有与它在同一语句树段且在同一语句结点下的右子树变量结点, 在遍历的
过程中将信息流信息写入信息流向图中。下面说明对于一个源变量结点, 遍历语句树段寻 找目标变量的过程, 以及在信息流树中寻找源变量结点的过程。
①遍历语句树段寻找目标变量的过程 :
a) 对树中某一语句树段中的一个源变量结点, 设有一指针 Q, 令其指向该源变量 结点的右指针指向的结点。
b) 如果 Q 指向结点是变量类型结点, 表示该结点记录的是目标变量, 找到一条信 息流, 将信息流信息写入信息流向图中。若此结点左指针不为空, 则 Q 指向其左指针指向的 结点, 跳至 b) ;
c) 若其左指针为空, 则 Q 指向其右指针指向的结点。若 Q 为空, 或 Q 指向结点为语 句结点 ( 表示 Q 已指向树中的下一个语句树段的根结点 ), 或 Q 指向结点与源变量结点不在 同一语句结点下 ( 表示 Q 指向的变量结点不在源变量的信息流作用域内 ), 则此次遍历结 束。
d) 如果 Q 指向结点是语句类型结点 ( 表示一个控制语句中嵌套了另一条控制语 句 ), 则 Q 指向它的右指针指向的结点, 跳至 b)。
e) 如果 Q 指向结点是 null 类型结点 ( 表示一个控制语句中嵌套了另一条紧邻的 控制语句 ), 表示则 Q 指向它的左子树结点, 跳至 b)。
②寻找源变量结点过程
设 P 为指向信息流树中某一源变量结点的指针, 假设根据上述遍历语句树段中目 标变量结点的过程, 已经找出了所有以 P 指向结点为源变量的信息流的目标变量结点, 接 下来要找到树中下一个源变量结点, 进行遍历, 则在树中寻找下一个源变量结点的过程如 下:
a) 如果 P 的左指针不为空, 则 P 指向它的左指针指向的结点, 此结点即为要找的下 一个源变量结点, 寻找过程结束。
b) 如果 P 的左指针为空, 则 P 指向它的右指针指向的结点。
c) 跳至第 b) 步, 直至 P 的左指针不为空。
d) 指向它的左指针指向的结点。
e) 如果 P 指向结点是语句结点, 则 P 指向它的左指针指向的结点, 此结点即为要找 的下一个源变量结点, 寻找过程结束。
对于上述生成共享资源矩阵并搜索隐通道步骤进一步说明如下 :
由于在信息流向图中已记录下共享变量在函数中的可见性和可修改性信息, 因此 矩阵的生成十分简单 ( 见具体实施方式中的共享资源矩阵生成算法 )。而到目前为止对隐 通道的研究仍然不能刻画出它的本质特征, 因此要给出隐通道充分且必要的判定条件并不 容易, 但可以依据隐通道存在的最小条件来缩小查找范围。
由于一个隐通道需要一个发送进程来修改共享变量, 以及一个接收进程发现变量 的修改, 即要求该共享变量兼具可见性和可修改性两种性质。如果某一共享变量只具有可 见性或只具有可修改性, 则该变量不能用于构成隐通道, 因此, 在经过传递闭包运算得出的 共享资源矩阵中, 找出在所有原语中只具有可见性或只具有可修改性的变量, 剔除这些变 量, 得到的矩阵中记录的就是同时具有可见性和可修改性的共享变量。
接下来, 利用剩下的共享变量进行隐通道分析。 分析是逐变量进行的, 对于某个变量, 首先找出和它相联系的原语操作, 然后运用系统的强制安全策略, 一般这种策略都遵从 bell-lapadula 模型, 即信息不能从高安全级传递到低安全级。因此, 只要发送方安全级高 于或等于接收者的安全级, 就产生一个潜在隐通道。分析开始时常假定发送者拥有高于或 等于接收者的安全级, 接着, 应用其中安全模型策略, 就可以发现共享变量构成的潜在隐通 道。这一分析重复进行, 就可以找出待分析系统中所有的潜在隐通道。
本发明方法提出了一种基于系统源代码搜索隐通道的信息流分析方法。本方法 基于系统源代码进行分析工作, 可以提高隐通道搜索工作的精度 ; 另外, 本方法中提出了一 套信息流描述和分析方法, 为基于系统源代码搜索隐通道的自动化进行提供算法和理论依 据; 并且在信息流分析过程中, 本方法避免了应用系统强制安全策略模型在源代码中的解 释, 采用与共享资源矩阵结合的方式, 从而避免引入伪非法流。 附图说明
图 1 是信息流分析方法工作流程示意图。 图 2 是词法分析器与信息流树构造交互的示意图。 图 3 是语句树段构造算法实现流程示意图。 图 4 是赋值语句树段构造算法实现流程示意图。 图 5 是函数调用和函数返回值语句树段构造算法实现流程示意图。 图 6 是控制语句树段构造算法实现流程示意图。 图 7 是实例中函数 os_creat_task 的信息流树和信息流图示意图。 图 8 是实例中共享资源矩阵输出示意图。 图 9 是实例中部分隐通道序列输出示意图。具体实施方式
下面根据附图对本发明作更详细的阐述, 并给出相应的算法描述。
本发明是一种基于系统源代码搜索隐通道的信息流分析方法, 以系统源代码中信 息流分析工作为前提, 结合共享资源矩阵法, 完成基于系统源代码的隐通道搜索工作。 根据 本发明方法提供的方法, 可以实现基于系统源代码搜索隐通道工作的自动化。
如图 1 所示, 本发明的信息流分析方法具体包括下列步骤 :
(1) 借助程序设计语言编译系统中的词法分析程序, 扫描系统源代码, 分别识别出 源代码中的函数和函数中的语句、 变量 ;
(2) 根据扫描程序识别出的函数以及函数调用语句, 确定函数间的调用关系, 构造 语句树段, 给出每个函数的函数依赖集 ;
(3) 根据扫描程序识别出的能产生信息流的语句和变量, 作为信息流分析的输入, 构造函数信息流树, 并进行剪枝 ;
(4) 遍历函数信息流树, 输出每个函数的信息流向图 ;
(5) 根据函数的信息流向图, 以函数依赖集为单位, 获得依赖集中函数间的共享变 量可见性和可修改性信息, 生成共享资源矩阵 ;
(6) 以共享资源矩阵作为输入, 搜索隐通道, 输出系统中存在的隐通道序列。
具体实施过程如下 :一、 利用词法分析器扫描系统源代码, 将源代码转化为二元式输出
为方便构造信息流树, 将词法分析程序稍作改动, 使得其可以以语句为单位, 每次 输出一个语句的记号序列, 作为构造语句树段算法的输入, 具体见图 2。
在图 2 中, 关键字表用来存放所有关键字, 表结构和内容是预先定义好的。字符表 用来存放扫描源代码时识别出的标识符, 是在对源代码进行词法分析时写入内容的, 字符 表包括全局变量字符表和局部变量字符表。 函数名表用来存放扫描源代码时识别出的函数 名, 也是在词法分析的过程中逐渐填充的。 在对源程序进行词法分析时, 当识别出一个输入 的字符串 ( 即词素 ) 时, 就可以通过查找关键字表、 字符表和函数名表, 来确定字符串是关 键字, 还是标识符, 或者是函数名, 从而将其以二元式的形式输出。
相关数据结构定义如下 :
(1) 二元式记号
将由词法分析生成的二元式以结构体的形式存放, 结构定义如下 :
此结构体中标识记号和记号属性的两个域分别是 syl 和 pos, 都采用整数类型 ; pos 域就用来描述记号的属性, 记录记号在各表中的位置。 一条语句中所有的记号序列都存 放在 buf[] 这个结构体数组中, 这个数组就为构造信息流树提供输入。
(2) 关键字表
关键字表结构定义如下 :
其中, 关键字表采用结构体数组形式存放, 数组中每一个记录有两个域, 分别存放 每一个关键字的拼写和它在关键字表中的位置 ; 此结构定义仅给出了一部分, 关键字全部 存放在此结构中。
(3) 字符表
考虑到要经常对字符表进行查找和字符串匹配操作, 所以采用哈希表存储结构来 存放字符表信息, 定义如下 :
其中, 结构体 BucketListRec 表示的是一个记录变量信息的结点, *name 域记录下 识别出的变量名, pos 域用来存放变量在表中存放的位置, 另有一个指针域 *next, 指向同 在一个哈希地址的下一个结点 ; 结构体类型的 HashNode 数组就描述了字符表, 由指向变量 信息结点的指针数组构成, 每一变量在指针数组中存放的位置 ( 即数组下标 ) 由哈希函数 生成。
二、 利用词法分析结果, 以二元式为输入, 构造信息流树
在构造函数信息流树时, 以词法分析程序输出的二元式序列为输入。扫描源代码 过程中, 每当一个函数体扫描结束后, 词法分析程序都输出一个 (-2, ) 二元式来标识函数 结束。 而词法分析程序何时输出这样的二元式标识, 即如何判断函数体的结束, 是通过在词 法分析程序中引入一个标识变量, 标识源代码中的 “{” 和 “}” : 在扫描一个函数时, 当出现 一个 “{” 时, 该标识变量就增 1 ; 当出现一个 “}” 时, 该标识变量就减 1。由于 “{” 和 “}” 必 定是成对出现的, 所以当标识变量变为 0 时, 即表示函数体部分结束, 此时, 输出一个 (-2, ) 二元式。以此为前提, 信息流树构造算法如下所示 :
上述算法中, 调用了 StmtInfTree 子程序来生成信息流树中的各个语句树段。该 程序根据不同的语句类型, 调用相应的子程序来构造语句树段, 算法流程如图 3、 4、 5、 6所 示。
三、 确定函数依赖集
在扫描源代码构造函数信息流树的同时, 还要根据输出的记号序列来确定函数间 的调用关系, 即生成函数依赖集, 以便得到调用了若干函数的原语间共享变量的可见性和 可修改性信息, 从而提供给隐通道搜索工具来进行隐通道分析工作。
为此, 下面给出确定函数调用关系的算法, 算法生成的函数间调用关系存放在函 数名表中。在介绍算法之前, 先给出函数名表的结构定义 :
下面给出函数依赖集生成算法 :这样, 在构造语句树段的过程中就记录下了函数间的调用关系, 并存放在函数名 表中, 由此可确定函数的依赖集。
四、 遍历信息流树, 生成信息流向图
选用邻接表作为信息流向图的存储结构, 其数据结构定义如下 :
结构体类型 Inforgraph 定义的即为图结构。其中, *funcname 域用来记录信息流 向图所属函数的函数名, para_state 用来标识该函数有无参数, vnum 域用来记录图中的结 点数, 即函数中出现的共享变量的个数, Nodelist 域是一个 Vnode 结构体类型的数组, 描 述的是图中存放共享变量信息的表头结点, 表头结点中的 *name 域用来存放共享变量名, Modify 域用来标识变量的可修改性, *firstarc 域指向一个单链表, 链表由若干个 ArcNode 结构体类型的结点链接而成, 用来存放以表头结点中为源变量的信息流中的目标变量。
依据前面阐述的遍历思想, 给出遍历信息流树生成信息流向图的算法 :
五、 扫描信息流向图, 生成共享资源矩阵, 搜索隐通道 先给出矩阵的结构定义 :用一个结构体和一个二维数组来描述矩阵结构, 其中结构体 Func 和 Variable 分 别记录源代码中出现的函数和共享变量, 其中 *name[] 是一个指向字符串的指针数组, 用 来记录函数或共享变量名, num 用来记录源代码中函数和共享变量的个数, 这两个结构体是 在词法分析程序扫描系统源代码时生成的, 当识别出函数及全局变量的定义或声明时, 就 将函数名和变量名、 以及数量分别写入 *name 域, 其中, Func 与 FunList 中函数的存放位置 相同。另外, Variable 中除记录共享变量名以外, 还需补充记录两个特殊的变量 : User_in 和 User_out, 分别对应矩阵中的用户输入和输出。 二维数组 Property[][] 用来记录一个共 享变量在各个函数中的可见性和可修改性信息, 和函数中用户的输入和输出信息。我们约 定, 若变量在某一函数中只具有可见性, 则用 “1” 来标识 ; 若只具有可修改性, 则用字符 “2” 来标识 ; 若两种性质兼具, 则用 “3” 来标识, 若两种性质都没有, 则用字符 “0” 标识。而对于 用户输入和输出, 若有输入, 则用 “1” 标识, 若有输出, 则用 “2” 标识, 否则为 “0” 。
根据函数信息流树的构造、 剪枝, 以及信息流向图的生成过程可知, 在某一函数信 息流向图中, 若某一变量其在图中头结点的 Modify 域中标记为 “1” , 则此变量在该函数中 具有可修改 ; 若图中记录了信息流 “A- > *” , 就说明变量 A 在此函数中具有可见性 ( 包括 直接可见性和间接可见性 )。 依据这一判断条件, 可以根据信息流向图生成记录函数中变量 可修性和可见性信息的矩阵, 存放在 Property[][] 中, 算法如下 :
上述算法生成的矩阵记录的是共享变量在每个函数中的可见性和可修改性的信 息, 而最终要提供给共享资源矩阵搜索方法作为输入的矩阵, 记录的应该是共享变量在原 语中 ( 即函数依赖集 ) 这两种性质的信息。因此, 还要根据函数依赖集和 Property[][] 数 组, 生成共享资源矩阵, 该矩阵中记录共享变量在每个函数依赖集中的可见性和可修改性 信息。 生成共享矩源矩阵的依据是 : 若某一函数中有一个共享变量具有某种性质, 则这一共 享变量在包括该函数的函数依赖集中也具有这种性质。共享资源矩阵生成算法如下所示 :
利用上述算法生成的共享资源矩阵, 就可以作为共享资源矩阵搜索方法的输入来 搜索系统中的隐通道。
实例分析
下面以一个功能较为简单的 RTX-430 实时多任务操作系统 (RTOS) 中的部分源代 码为例, 来说明本发明方法的应用情况。
在这一 RTX-430 实时多任务操作系统中, 采用的是 “占先式内核” 任务调度机制, 即当一个低优先级的任务正在运行时, 一个高优先级的任务就绪, 那么 RTOS 就会把低优先 级的任务挂起, 来运行高优先级的任务 ; 等高优先级的任务执行了一个循环挂起之后, 再回
到低优先级任务的断点继续运行。 下面将有选择的介绍一些函数的功能及函数间的全局变 量代表的意义。
函数主要有 :
(1)os_system_init : 操作系统初始化, 进行任务栈、 任务延时计数、 任务状态的初 始化。
(2)os_system_start : 操作系统启动运行, 在系统初始化完成后, 系统直接切换到 最高优先级的任务, 多任务系统启动。
(3)os_create_task : 创建一个任务, 如果要创建的任务已经存在, 则返回出错信 息。
(4)os_delete_task : 撤消一个任务, 若要撤消的任务不存在, 则返回出错信息。
(5)task_switch : 任务切换, 此函数先把每个任务的延时数减 1, 然后再找出最高 优先级的就绪任务, 并切换到这个就绪任务。
相关的全局变量主要有 :
(1)STKP[] : 指向前一任务堆栈的尾地址 ;
(2)RTX_RobinTime : 每个任务最长的运行周期 ;
(3)TASK_Current : 当前运行的任务号 ;
(4)STATE[] : 标识每个任务的状态 ;
以其中的 os_create_task 函数为例, 给出根据本方法为其构造的信息流树及信 息流向图, 见图 7, 下面列出该函数的源代码 :
在得到每个函数的信息流树及信息流图之后, 我们借助前面给出的矩阵生成算法 得到该系统的共享资源矩阵如图 8 所示。结合共享资源矩阵方法, 得到该系统中可能存在 的隐通道序列见图 9。图中的 SENDER 列表示可能的发送方, RECIEVER 列则表示可能的接收 方, 而 SHARED VARIABLE 列是它们之间可能用来隐蔽传输的共享资源。
经过分析发现 : 在该系统实施实时多任务处理功能模块中, 提供的创建任务原语、 撤消任务原语等一些操作存在着隐通道漏洞, 有安全隐患。