finish 5.4

This commit is contained in:
firmianay 2018-04-03 17:03:37 +08:00
parent 46deb0748b
commit c6cebca6dd
9 changed files with 122 additions and 0 deletions

View File

@ -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
```

BIN
pic/5.4_cfg1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
pic/5.4_cfg2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
pic/5.4_cg1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,9 @@
digraph {
0 [label="contrived_caller"];
1 [label="contrived"];
2 [label="kfree"];
0 -> 1;
0 -> 2;
1 -> 2;
}

View File

@ -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="分配"];
}