介绍用来提高Linux应用程序安全性和可靠性的开源工具和代码追踪技术。

一、源代码检查工具

在软件开发过程中,我们可以利用源码检查工具来找出常见的编程错误以及安全漏洞。这些工具用起来并不复杂,下面介绍splint和flawfinder这两款源码检查工具的使用方法。

splint是一款静态源代码检查工具,能对源代码进行全面的分析。对于没有注释的源代码,可以使用-weak选项:

splint -weak *.c -I./inc

其中,./inc是头文件所在的子目录。此外,Splint还支持标准检查模式(选项-standard),若要进行中等强度检查则使用选项-checks,若使用选项-strict则进行最严格的检查。

flawfinder也是一款用来寻找源代码错误的静态分析工具。通过该工具提供错误消息,开发人员可以更快的找到错误所在。请看下面的例子:

$ flawfinder test.c

test.c:11: [2] (buffer) char:

Statically-sized arrays can be overflowed. Perform bounds

checking, use functions that limit length, or ensure that

the size is larger than the maximum possible length.

$

本例中,flawfinder给出了一个提示,指出静态尺寸的数组可能被恶意利用的潜在危险。

除了上面介绍的splint和flawfinder这两款工具外,还有RATS(一款安全审计工具)以及ITS4(静态漏洞扫描工具)等工具可用。但需要

注意的是,虽然这些工具能够分担一部分工作,但却无法完全替代人类。因为工具在发现漏洞的同时,也可能遗漏安全漏洞。

二、代码跟踪技术

我们知道,strace工具通常是用来追踪系统调用的,实际上,它还可以作为间接的源代码审计工具。从系统调用的角度来跟踪应用程序的执行,可以让我们了解到Linux应用程序的底层操作,借助这些低层操作我们可以更好的理解我们的源代码。

在下面的例子中,有多处违反了我们前面讨论的代码淬火原则,现在我们展示如何利用strace来进行调试。

#include <unistd.h>

#include <fcntl.h>

#define MAX_BUF 128

int main()

{

int fd;

char buf[MAX_BUF+1];

fd = open( "myfile.txt", O_RDONLY );

read( fd, buf, MAX_BUF );

printf( "read %s\n", buf );

close( fd );

}

我们注意到,上面的代码的第11行,即:fd = open( "myfile.txt", O_RDONLY

);

试图打开一个称为myfile.txt的文件,但事前并没有检查该文件是否业已存在。在这种情况下执行该程序的话,会导致无法预测的结果:

$ gcc -o bad bad.c

$ ./bad

read @?8Z@

$

看看,这样的结果是你没料到的吧。所以,先让我们利用strace来看看到底发生了什么。注意,下面的输出已经作了删减,但重要的信息都保留下来了:

$ strace ./bad

execve("./bad", ["./bad"], [/* 20 vars */]) = 0

uname({sys="Linux", node="camus", ...}) = 0

...

open("myfile.txt", O_RDONLY) = -1 ENOENT ( No such file or

directory)

read(-1, 0xbfffef20, 128) = -1 EBADF (Bad file descriptor)

fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0

mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,

-1, 0) = 0x40017000

write(1, "read \300\357\377\2778Z\1@\n", 14read /à???8z@

) = 14

close(-1) = -1 EBADF (Bad file descriptor)

munmap(0x40017000, 4096) = 0

exit_group(-1) = ?

$

执行程序后,我们看到用来启动该程序的系统调用是execve();不久又调用了open(),该系统调用对应于代码中的第11行。并且我们看到系统调用

open()的右边的返回值是-1,并指出错误"ENOENT ( No such file or

directory)",即不存在这个文件或目录。换句话说,这是在告诉我们需要先建立文件。此外,系统调用read()也以失败而告终,它的错误是非法

的文件描述符,因为open调用失败了。

strace工具不仅用来帮助理解有源代码的程序的行为,而且也对于没有源代码的程序也同样有效。因为,透过对系统调用的观察,我们能够在二进制级别来理解程序的行为。

三、小结

古人云,工欲善其事,必先利其器。借助于上文介绍的代码淬火方面的编码知识,用来提高Linux应用程序安全性和可靠性的调试工具,相信读者能够更快更好开发出安全可靠的高品质软件来。