diff --git a/doc/5.4_dataflow_analysis.md b/doc/5.4_dataflow_analysis.md index 840b4f3..2516c98 100644 --- a/doc/5.4_dataflow_analysis.md +++ b/doc/5.4_dataflow_analysis.md @@ -204,3 +204,64 @@ p = *q; ## 实例分析 +#### 检测指针变量的错误使用 +在检测指针变量的错误使用时,我们关心的是变量的状态。 + +下面看一个例子: +```c +int contrived(int *p, int *w, int x) { + int *q; + if (x) { + kfree(w); // w free + q = p; + } + [...] + if (!x) + return *w; + return *q; // p use after free +} +int contrived_caller(int *w, int x, int *p) { + kfree(p); // p free + [...] + int r = contrived(p, w, x); + [...] + return *w; // w use after free +} +``` +可以看到上面的代码可能出现 use-after-free 漏洞。 + +这里我们采用路径敏感的数据流分析,控制流图如下: + +![](../pic/5.4_cfg1.png) +![](../pic/5.4_cfg2.png) + +调用图如下: + +![](../pic/5.4_cg1.png) + +下面是用于检测指针变量错误使用的检测规则: +``` +v 被分配空间 ==> v.start +v.start: {kfree(v)} ==> v.free +v.free: {*v} ==> v.useAfterFree +v.free: {kfree(v)} ==> v.doubleFree +``` + +分析过程从函数 contrived_call 的入口点开始,对于过程内代码的分析,使用深度优先遍历控制流图的方法,并使用基本块摘要进行辅助,而对于过程间的分析,选择在遇到函数调用时直接分析被调用函数内代码的方式,并使用函数摘要。 + +函数 contrived 中的路径有两条: +- BB0->BB1->BB2->BB3->BB5->BB6:在进行到 BB5 时,BB5 的前置条件为 p.free, q.free 和 w.free,此时语句 `q1 = *q` 将触发 use-after-free 规则并设置 q.useAfterFree 状态。然后返回到函数 contrived_call 的 BB2,其前置条件为 p.useAfterFree, w.free,此时语句 `w1 = *w` 设置 w.useAfterFree。 +- BB0->BB1->BB3->BB4->BB6:该路径是安全的。 + +#### 检测缓冲区溢出 +在检测缓冲区溢出时,我们关心的是变量的取值,并在一些预定义的敏感操作所在的程序点上,对变量的取值进行检查。 + +下面是一些记录变量的取值的规则: +``` +char s[n]; // len(s) = n +strcpy(des, src); // len(des) > len(src) +strncpy(des, src, n); // len(des) > min(len(src), n) +s = "foo"; // len(s) = 4 +strcat(s, suffix); // len(s) = len(s) + len(suffix) - 1 +fgets(s, n, ...); // len(s) > n +``` diff --git a/pic/5.4_cfg1.png b/pic/5.4_cfg1.png new file mode 100644 index 0000000..a9df3a7 Binary files /dev/null and b/pic/5.4_cfg1.png differ diff --git a/pic/5.4_cfg2.png b/pic/5.4_cfg2.png new file mode 100644 index 0000000..69d1748 Binary files /dev/null and b/pic/5.4_cfg2.png differ diff --git a/pic/5.4_cg1.png b/pic/5.4_cg1.png new file mode 100644 index 0000000..fd76121 Binary files /dev/null and b/pic/5.4_cg1.png differ diff --git a/pic/5.4_state.png b/pic/5.4_state.png index 1179e50..cb700a7 100644 Binary files a/pic/5.4_state.png and b/pic/5.4_state.png differ diff --git a/src/Others/5.4_dataflow_analysis/cfg1.gv b/src/Others/5.4_dataflow_analysis/cfg1.gv new file mode 100644 index 0000000..655a6d6 --- /dev/null +++ b/src/Others/5.4_dataflow_analysis/cfg1.gv @@ -0,0 +1,22 @@ +digraph { + labelloc = "title"; + label = "int contrived(int *p, int *w, int x)"; + node [shape="record"]; + + bb0 [label="BB0"]; + bb1 [label="BB1: if(x)"]; + bb2 [label="BB2: param w"]; + bb3 [label="BB3: x1 =! x"]; + bb4 [label="BB4: w1 = *w"]; + bb5 [label="BB5: q1 = *q"]; + bb6 [label="BB6"]; + + bb0 -> bb1; + bb1 -> bb2; + bb1 -> bb3; + bb2 -> bb3; + bb3 -> bb4; + bb3 -> bb5; + bb4 -> bb6; + bb5 -> bb6; +} \ No newline at end of file diff --git a/src/Others/5.4_dataflow_analysis/cfg2.gv b/src/Others/5.4_dataflow_analysis/cfg2.gv new file mode 100644 index 0000000..10f8f37 --- /dev/null +++ b/src/Others/5.4_dataflow_analysis/cfg2.gv @@ -0,0 +1,20 @@ +digraph { + labelloc = "title"; + label = "int contrived_caller(int *w, int x, int *p)"; + node [shape="record"]; + + bb0 [label="BB0"]; + bb1 [label="BB1: param p\n + call kfree\n + param p\n + param w\n + param\n + call contrived"]; + bb2 [label="BB2: r = ret\n + w1 = *w"]; + bb3 [label="BB3"]; + + bb0 -> bb1; + bb1 -> bb2; + bb2 -> bb3; +} \ No newline at end of file diff --git a/src/Others/5.4_dataflow_analysis/cg.gv b/src/Others/5.4_dataflow_analysis/cg.gv new file mode 100644 index 0000000..2074a15 --- /dev/null +++ b/src/Others/5.4_dataflow_analysis/cg.gv @@ -0,0 +1,9 @@ +digraph { + 0 [label="contrived_caller"]; + 1 [label="contrived"]; + 2 [label="kfree"]; + + 0 -> 1; + 0 -> 2; + 1 -> 2; +} \ No newline at end of file diff --git a/src/Others/5.4_dataflow_analysis/sm.gv b/src/Others/5.4_dataflow_analysis/sm.gv new file mode 100644 index 0000000..e447064 --- /dev/null +++ b/src/Others/5.4_dataflow_analysis/sm.gv @@ -0,0 +1,10 @@ +digraph { + 0 [style="filled"]; + 2 [shape="doublecircle"]; + 3 [shape="doublecircle"]; + + 0 -> 2 [label="被使用"]; + 0 -> 3 [label="释放"]; + 0 -> 1 [label="释放"]; + 1 -> 0 [label="分配"]; +} \ No newline at end of file