我所知道的避免缓冲区溢出的最佳方法是使用 100% 完全详尽的单元测试来检查处理任何大小和类型的缓冲区的任何函数。当然,这并不总是现实的。
“详尽”意味着考虑到所有可能的情况,无论您的应用程序是否会在您第一次编写代码时生成所有这些特定情况。
尽管有一些工具可以在该领域为您提供帮助。有些自动化程度很高,会自动生成单元测试。我从来没有尝试过其中任何一个,所以我不能保证其中任何一个,但如果你处于时间紧缩状态,那可能会有所帮助。
另一种可行的方法是针对您的代码运行静态分析器。 Code Coverity 是我过去使用过的,但也有很多其他的。在大多数情况下,静态分析只会发现您在堆栈上声明静态缓冲区的问题,如下所示:
char buf[256];
...
char a = buf[256]; // <- bug here, although not too bad
buf[256] = a; // <- bug here, could be bad, you're writing to the stack!
现在...在 Unix 下,缓冲区溢出有两个问题。在大多数情况下,它会使您的系统崩溃。但是,如果黑客可以访问您的代码,他们可能能够调用特定的系统函数(明确地说是内核函数)。在这种情况下,潜在的问题是您的进程是否以提升的用户身份运行(即最坏的情况:root)。那时,黑客可能已经获得了一些权限,可以在未经您授权的情况下做更多事情。要消除这种风险,您有两个主要解决方案:
- 使用 chroot 环境;如果您是 Linux 新手,这可能很难设置,但它适用于虚拟所有 Unices
- 使用 virtualbox 环境(或其他一些虚拟系统,如 qemu);获得这样的环境设置通常很容易,但如果您想自动生成新环境......有一个 API,这可能很乏味。
还有最后一种方法,但这可能会很慢。 CPU有一个MMU。您可以使用 MMU 保护/取消保护内存,并确保每次读取和写入都发生在已分配的缓冲区上(如果是堆栈,则使用帧缓冲区来确保您在正确的窗口内。)可以想象,对于每次写入(可能还有多次读取),您都会收到一个中断,并且处理程序并不小。这是一个很好的工具/想法来调试一个有很多缓冲区溢出的软件,但一般来说它在生产中是不可用的。
很遗憾,默认情况下,这些选项都不是 g++ 套件的一部分。