" safe"有什么区别?和"不安全" C / C ++中的代码?
我已经读过" C ++在导致严重安全漏洞的方面是不安全的。在文章中:How Rust Compares to Other Languages and More 。什么是不安全的代码不安全?
答案 0 :(得分:7)
我相信John Regehr的文章A Guide to Undefined Behavior in C and C++, Part 1很好地概述了这篇文章的内容:
编程语言通常区分正常 计划行动和错误行动。对于图灵完整的语言 我们无法可靠地决定某个程序是否具有潜力 执行错误;我们必须运行它并看到。
在安全的编程语言中,错误会在发生时被捕获。 例如,Java通过其异常系统在很大程度上是安全的。在一个 不安全的编程语言,错误没有被困。相反,之后 执行一个错误的操作,程序继续前进,但在一个 无声的错误方式可能会在以后产生可观察到的后果。 Luca Cardelli关于类型系统的文章有一个很好的清晰介绍 对这些问题。 C和C ++在强烈意义上是不安全的:执行一个 错误的操作会导致整个程序毫无意义,如 反对只有不可预测的错误操作 结果。在这些语言中,据说有错误的操作 未定义的行为。
因此,一旦我们进入未定义行为的领域,我们现在就拥有“unsafe”代码。另一篇将未定义行为视为不安全代码的好文章是What Every C Programmer Should Know About Undefined Behavior #2/3:
在我们系列的第1部分中,我们讨论了未定义的行为是什么,以及 它如何使C和C ++编译器产生更高的性能 应用程序比“安全”语言。这篇文章谈到“不安全”的方式 C确实是,解释了一些非常令人惊讶的效果 未定义的行为可能导致。在第3部分中,我们讨论了什么是友好的 编译器可以做些什么来缓解一些意外,即使它们不是 要求。
我喜欢称之为“为什么未定义的行为通常是一种可怕的行为 C程序员的可怕之处“。: - )
C和C ++由它们各自的标准和we can find links to the latest ones here指定,并且那些标准将许多行为指定为未定义的行为。这基本上意味着行为是不可预测的。 C ++标准定义了未定义的行为,如下所示:
本国际标准没有要求的行为 [注意:当本国际标准忽略任何明确的定义时,可能会出现未定义的行为 行为或程序使用错误的构造或错误数据时。允许的未定义行为 范围从完全忽略情况与不可预测的结果,到翻译期间的行为或 程序以环境特征的文件形式执行(有或没有发行 诊断消息),终止翻译或执行(发布诊断消息)。 许多错误的程序结构不会产生未定义的行为;他们需要被诊断出来。 - 后注]
编译器不需要为未定义的行为提供诊断,我们可以找到许多未定义行为导致安全漏洞的情况,其中一个较为人知的案例可能是Linux kernel null pointer check removal:
这个想法是寻找在C / C ++编译器时变得死的代码 关于利用未定义的行为是明智的。经典的例子 几年前在Linux内核中发现了这类错误。 代码基本上是:
struct foo *s = ...; int x = s->f; if (!s) return ERROR; ... use s ...
问题是第2行中s的取消引用允许编译器 推断s不为null(如果指针为null则为函数 未定义;编译器可以简单地忽略这种情况)。就这样 第3行中的null check得到了静默优化,现在是内核 如果攻击者可以找到一种方法来调用,则包含可利用的漏洞 这段代码带有空指针
大多数情况下,避免未定义的行为是一个良好的编码实践问题:
并使用ubsan等正确的工具,但可能会出现一些模糊的情况,例如infinite loops许多开发人员可能会感到惊讶。