“getenv ...函数...可能不安全”-真的吗?

Posted

技术标签:

【中文标题】“getenv ...函数...可能不安全”-真的吗?【英文标题】:"getenv... function ... may be unsafe" - really? 【发布时间】:2018-02-01 17:40:07 【问题描述】:

我正在使用 MSVC 编译一些使用标准库函数的 C 代码,例如 getenv()sprintf 等,并设置了 /W3 用于警告。 MSVC 告诉我:

'getenv':这个函数或变量可能不安全。考虑改用 _dupenv_s。要禁用弃用,请使用 _CRT_SECURE_NO_WARNINGS

问题:

与在其他平台上使用相比,理论上为什么这不安全? 实际上在 Windows 上是否不安全? 假设我没有编写面向安全的代码 - 我应该禁用此警告还是实际开始为一堆标准库函数起别名?

【问题讨论】:

你看这里了吗:***.com/questions/4286934 wiki.sei.cmu.edu/confluence/display/c/… 【参考方案1】:

getenv() 可能是不安全的,因为对同一函数的后续调用可能会使先前返回的指针无效。因此,诸如

之类的用法
char *a = getenv("A");
char *b = getenv("B");
/* do stuff with both a and b */

可能会中断,因为无法保证 a 在那时仍然可用。

getenv_s() - 自 C11 起在 C 标准库中可用 - 通过立即将值复制到调用者提供的缓冲区中来避免这种情况,调用者可以完全控制缓冲区的生命周期。 dupenv_s() 通过让调用者负责管理已分配缓冲区的生命周期来避免这种情况。

然而,getenv_s 的签名有些争议,并且该函数甚至可能在某个时候从 C 标准中删除...参见this report。

【讨论】:

根据 cocppreference,C++11 及更高版本并非如此。对 POSIX setenv()、unsetenv() 和 putenv() 的调用可能会使旧结果无效,但对 getenv 的其他调用则不会。 @AndrewPenkrat:C11 怎么样? @einpoklum 对于 C11,这仍然是一个问题,并且在那里引入了 getenv_s。然而,这个问题有 C 和 C++ 标签,而当前的答案只涵盖 C 语言。 那么用 _dupenv_s 重写 getenv("environment_variable") 的确切方法是什么?【参考方案2】:

getenv 与许多经典的 C 标准库一样,没有限制字符串缓冲区的长度。这就是缓冲区溢出等安全漏洞的常见来源。

如果您查看getenv_s,您会发现它提供了对返回字符串长度的明确限制。 Security Development Lifecycle 最佳实践建议所有编码都使用它,这就是 Visual C++ 对不太安全的版本发出弃用警告的原因。

见MSDN和this blog post

Microsoft 努力让 C/C++ ISO 标准库包含安全 CRT here,其中一些已被批准用于 C11 Annex K,如 here 所述。这也意味着getenv_s 应该通过引用成为 C++17 标准库的一部分。也就是说,附件 K 被官方认为是可选的一致性。这些函数的 _s 边界检查版本仍然是 C/C++ 社区中一些 debate 的主题。

【讨论】:

但是getenv()的接口没有调用者提供缓冲区。那么风险在哪里?只要库本身没有引入错误,即没有超出任何内容,并确保返回 '\0'-terminated-string - 调用者是完全安全的。还是我错过了什么?当然返回环境字符串的长度更好,但这与安全无关。 如果函数在多线程环境中使用,那么当有人正在读取缓冲区时,缓冲区可能会被修改。它也不是可重入的,这意味着如果在读取缓冲区时,您进行了一个最终也调用 getenv() 的函数调用,那么值可能会意外更改。

以上是关于“getenv ...函数...可能不安全”-真的吗?的主要内容,如果未能解决你的问题,请参考以下文章

真的要听妈妈的话。

HTTPS 为啥安全? 真的安全吗?

三丰云真的太好了

IRQBalance真的有效么?

真的有必要用rxjava吗

你认为血缘关系真的很重要吗?