c - memset 如何提供比 bzero 或 explicit_bzero 更高的安全性?

标签 c

bzero 的手册页声明出于各种安全原因,它已被弃用,memset应该改用。他们主要指的是这个问题,即bzeroexplicit_bzero找不到给定数据的所有副本(尤其是小到可以放入寄存器的数据),并且可能没有按预期完全删除或覆盖。但是 memset只接受一个指针地址。应该如何memset能否找到所有副本来关闭这种缺乏安全性?

最佳答案

我认为您误读了手册页。假设您正在谈论 Linux 手册页,它声称(正确)explicit_bzeromemset_explicitmemset_smemset 更安全(出于某些目的)和 bzero .它没有声称 memset 之间有任何安全差异。和 bzero .原因bzero不推荐使用的是它是 memset 周围的一个微不足道的包装器并且所有¹ C 实现都有 memset ,所以程序员不妨使用memset .
memset 之间的区别/bzeroexplicit_/_s变体是禁止编译器优化显式变体。这使得显式变体适用于清理 secret 数据。例如,考虑以下程序片段:

bzero(password, password_length);
free(password);

只需 bzeromemset ,许多现代编译器看到“哦,你正在写入内存然后释放它。没有办法回读 bzero 的内容刚刚写了,所以调用bzero相当于什么都不做。什么都不做比调用 bzero 更快,因此我不会为 bzero 生成任何代码称呼。”

编译器推理的缺陷在于,将内存归零的原因不是程序的已定义行为,而是在后续未定义或未指定行为的情况下会发生什么。从 C 编译器的角度来看,未定义的行为意味着任何事情都可能发生。从安全工程师的角度来看,对于未定义的行为(例如缓冲区溢出或释放后使用)究竟会发生什么是非常重要的。同样,从未初始化的内存中读回的确切内容是未指定的,但对安全工程师来说很重要。安全工程师试图减少这种未定义或未指定行为的安全影响。

所以对于安全工程师来说 memset 的优化很不幸。一位安全工程师想要保证当内存被释放时,its former contents will not leak out, even, say, due to a buffer overflow .因此explicit_bzero : 编译器被指示在此函数返回时将目标内存的内容视为可观察的,因此不允许他们基于程序没有从它读回来优化调用。语义上,explicit_bzero(buffer, length)相当于
bzero(buffer, length);
for (size_t i = 0; i < length; i++) __observe__(buffer[i]);

在哪里 __observe__没有效果,但仍然取决于其参数的值。因此不允许编译器删除对 bzero 的调用。 , 因为那时 __observe__不会读回正确的值。

显式归零有局限性。手册页强调它不会清除寄存器中变量的副本,但这通常不是一个大问题,因为缓冲区溢出或从未初始化的内存读取最终导致寄存器值泄漏的情况很少见。实践中最大的限制是realloc .当您使用动态分配的内存时,realloc可能会移动它,并且没有办法擦掉旧值。因此,如果缓冲区的内容是敏感的,则不能使用 realloc在上面。

显式归零的另一个限制是它仅适用于程序级别,而不适用于系统级别。数据的副本可能保留在缓存、交换等中。将程序内的内存归零的目的是为了防止程序内的安全漏洞。它不能防止更大的系统妥协。

请注意,编写自己的 explicit_bzeroimpossible to do portably .您能做的最好的事情就是让它与有限编译器的有限版本集一起工作,但不能保证下一个版本不会有一个更高级的优化器可以看穿您的尝试。这就是 C11 将其作为标准功能添加到 memset_s 的原因。 .

¹几乎。技术上独立的实现不必有 memset但它是如此简单而有用的功能,大多数人都这样做,而且它通常由编译器提供,因此即使在没有通常的 C 运行时构建时也可以使用它。

关于c - memset 如何提供比 bzero 或 explicit_bzero 更高的安全性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53792077/

相关文章:

c - 图像大小调整程序输出扭曲的图像

c - 两个大数相加只用C

c - C中的BST遍历

c - mkdir 函数在 C 中不起作用

c - int 意外变回初始状态

c - 使用 libcurl 下载单词

c - 从字符串中获取整数

c - 在 C 中使用可变参数函数进行字符串连接

c++ - 计算 C 数组中三元组的频率以进行索引

c - 链表插入简单