一、源代码检查工具
在软件开发过程中,我们可以利用源码检查工具来找出常见的编程错误以及安全漏洞。这些工具用起来并不复杂,下面介绍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应用程序安全性和可靠性的调试工具,相信读者能够更快更好开发出安全可靠的高品质软件来。
没有评论:
发表评论