【问题标题】:How to safely zero std::array?如何安全地将 std::array 归零?
【发布时间】:2022-01-30 20:04:54
【问题描述】:

我正在尝试安全地在类析构函数中将std::array 归零。 安全地,我的意思是我想确保编译器永远不会优化这个归零。这是我带来的:

template<size_t SZ>
struct Buf {
    ~Buf() {
        auto ptr = static_cast<volatile uint8_t*>(buf_.data());
        std::fill(ptr, ptr + buf_.size(), 0);
    }

    std::array<uint8_t, SZ> buf_{};
};

此代码是否按预期工作?无论如何,volatile 关键字会阻止编译器优化吗?

【问题讨论】:

  • 你为什么要那个
  • 要安全地擦除内存,您需要使用一些专门用于该目的的平台/编译器特定功能。标准 C++ 无法保证。您对哪个平台/编译器感兴趣?
  • 这能回答你的问题吗? How-to write a password-safe class?
  • 我认为 C++ 标准保证这一点。实际上,如果您确实确保将一些 RAM 清零,操作系统仍有可能在交换存储中留下一个副本。
  • 易失性转换确保机器将实际执行写操作并将内存归零。它是否会提供任何安全性是任何人的猜测,因为您的威胁没有明确说明,但我的猜测在“否”方面是坚定的。

标签: c++


【解决方案1】:

C++ 标准本身并没有做出明确的保证。它说:

[dcl.type.cv]

通过 volatile 左值访问的语义是实现定义的。 ...

[注 5:volatile 是对实现的提示,以避免涉及对象的激进优化,因为对象的值可能会通过实现无法检测到的方式进行更改。 此外,对于某些实现,易失性可能表示需要特殊的硬件指令才能访问该对象。 有关详细语义,请参见 [intro.execution]。 通常,volatile 的语义在 C++ 中与在 C 中的语义相同。 ——尾注]

尽管 C++ 标准缺乏保证,但通过指向 volatile 的指针覆盖内存是一些加密库清除内存的一种方式 - 至少作为系统特定功能不可用时的后备。

附:我建议改用const_cast,以避免意外转换为不同类型而不是不同限定的相同类型:

auto ptr = const_cast<volatile std::uint8_t*>(buf_.data());

隐式转换也可以:

volatile std::uint8_t* ptr = buf_.data();

用于此目的的系统特定函数是 Windows 中的 SecureZeroMemory 和某些 BSD 和 glibc 中的 explicit_bzero

C11 标准为此提供了一个可选函数 memset_s,它也可能在 C++ 中可供您使用,但当然不能保证可用。

有一个提议P1315 引入与 C++ 标准类似的功能。


请注意,安全擦除并不是将敏感数据泄露的可能性降至最低的唯一考虑因素。例如,除非指示不这样做,否则操作系统可能会将内存交换到永久存储上。在 C++ 中没有标准的方法来制作这样的指令。 POSIX 中有mlock,Windows 中有VirtualLock

【讨论】:

  • memset_s 似乎不保证与此相关的任何事情。
  • @aschepler 为什么不将Unlike memset, any call to the memset_s function shall be evaluated strictly according to the rules of the abstract machine as described in (5.1.2.3). That is, any call to the memset_s function shall assume that the memory indicated by s and n may be accessible in the future and thus must contain the values indicated by c. 视为与此相关的保证?
  • @eerorika 有趣的是,cppref 声明一个选项是 std::fill,此处的注释中有易失性指针:en.cppreference.com/w/cpp/string/byte/memset
  • 糟糕,我只看了en.cppreference.com/w/c/string/byte/memset 中的功能描述,并没有说清楚。严格的评估在后面的注释中解释。
猜你喜欢
  • 2012-12-27
  • 2021-08-11
  • 2017-01-28
  • 1970-01-01
  • 2011-08-07
  • 2022-01-02
  • 2021-07-21
  • 1970-01-01
  • 2014-03-12
相关资源
最近更新 更多