【问题标题】:Protecting heap data when a program is halted程序停止时保护堆数据
【发布时间】:2015-10-04 08:28:25
【问题描述】:

假设我有一个程序可以解密文件并将解密的内容存储在堆上。我想保护这些信息免受在同一系统上运行的其他(非根)进程的影响,所以在我调用free() 释放堆分配之前,我使用memset() 覆盖数据并使其不可用下一个使用相同物理内存的进程。 (I understand this isn't a concern on some systems,但宁愿在安全方面犯错。)

但是,我不确定在程序无法正常终止的情况下该怎么办,无论是通过强制终止(SIGINTSIGTERM 等)还是由于错误条件(@987654326 @、SIGBUS 等)。我应该在退出之前捕获尽可能多的信号以清除堆,还是有更有序的做事方式?

【问题讨论】:

    标签: c security unix memory


    【解决方案1】:

    从安全角度来看,在进程之间泄漏内存内容(尤其是具有不同权限)的操作系统会被严重破坏,以至于您自己执行此操作不会改变任何内容。特别是因为在大多数操作系统上,您写入的内存页面可以随时从您手中夺走,换出并交给其他人。因此,我可以肯定地说,除非您使用的操作系统非常专业,以至于没有任何人可以向其泄漏内存,否则您无需担心正常终止。此外,有一些方法可以在您无法捕捉到终止信号的情况下终止您的进程,因此您无论如何都无法处理所有情况。

    当涉及到异常终止(SIGSEGV 等)时,最好的办法是禁用转储核心,或者至少确保您的核心转储只能由您读取。这应该是主要担心,物理内存不会泄漏,但您的核心转储可能会被其他人读取。

    话虽如此,当您不再需要它们时,从内存中清除它们仍然是一个非常好的做法。不是因为他们可以通过正常操作泄露给别人,因为他们不能,而是因为他们可以通过bug泄露出去。你可能有一个可利用的错误,也许你得到一个要写入日志的流浪指针,也许你会把你的密钥留在堆栈上然后忘记初始化你的数据等等。所以你的主要担心不应该是在退出之前从内存中清除秘密,但要实际识别代码中不再需要秘密的点并立即清除它。

    不幸的是,使用您提到的memset 是不够的。今天的许多编译器都足够聪明,可以理解您对memset 的一些调用是死存储并将它们优化掉(例如在离开函数之前或在free 之前的堆栈缓冲区的memset)。请参阅this issue in LibreSSL 了解有关它的讨论,以及this implementation of explicit_bzero 了解目前最知名的在clang 和gcc 上解决它的尝试。

    【讨论】:

    • 谢谢!因此,假设操作系统在将内存分配给不同的进程之前会总是清除内存内容是相当安全的吗? (这似乎是 OS X、Debian 和 Ubuntu 的行为方式,但我找不到任何明确的参考资料。)
    • 我已经讨论过几次,唯一的结论是“这很明显(对于操作系统开发人员),甚至没有在任何地方记录”。除了malloc&co 之外,POSIX 没有任何方法可以从操作系统获取匿名内存,具有通常的语义,因此没有任何帮助。但是为了提供进程的安全分离,内存必须在被分配给其他人之前被清除。没有其他方法可以做到这一点。一个标准律师能不能做出一个不这样做的操作系统?当然可以,但我怀疑它会被使用。我不知道今天有人做了什么不同的事情。
    • 好吧,也许这一切都在 POSIX 和 ANSII 标准之间的灰色地带,但我希望他们能在这样的问题上做出更多的努力来解释自己。在调用free() 之前优化对memset() 的调用简直是愚蠢的。无声无息地这样做是犯罪愚蠢的。
    猜你喜欢
    • 1970-01-01
    • 2016-11-11
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多