我们有一些生产中没有人关心的构建系统,这些机器运行古老版本的GCC,如GCC 3或GCC 2.
而且我无法说服管理层将其升级到更近期:他们说,"如果没有破产,就不要修理它".
由于我们维护了一个非常古老的代码库(写于80年代),这个C89代码在这些编译器上编译得很好.
但我不确定使用这些旧东西是个好主意.
我的问题是:
可以使用旧的C编译器破坏编译程序的安全性吗?
更新:
相同的代码是由Visual Studio 2008 for Windows目标构建的,而MSVC还不支持C99或C11(我不知道更新的MSVC是否支持),我可以使用最新的GCC在我的Linux机器上构建它.因此,如果我们只是放入一个较新的GCC,它可能会像以前一样好.
plu*_*ash 103
实际上我会反驳.
在许多情况下,C标准未定义行为,但很明显在给定平台上使用"哑编译器"会发生什么.允许有符号整数溢出或通过两种不同类型的变量访问相同内存的情况.
gcc(和clang)的最新版本已经开始将这些案例视为优化机会,如果它们改变了二进制文件在"未定义行为"条件下的行为方式,则无法照顾它们.如果您的代码库是由处理C的人编写的,就像"便携式汇编程序"一样,这是非常糟糕的.随着时间的推移,优化器在进行这些优化时开始考虑越来越大的代码块,这增加了二进制文件最终会做"除了由哑编译器构建的二进制文件"之外的其他事情的机会.
有编译器开关来恢复"传统"行为(-fwrapv和-fno-strict-aliasing用于我上面提到的两个),但首先你要了解它们.
虽然原则上编译器错误可能会将符合规范的代码转变为安全漏洞,但我认为在宏观方案中这种风险可以忽略不计.
Mat*_* M. 52
两种行动方案都存在风险.
较旧的编译器具有成熟的优点,并且其中的任何内容都可能(但不能保证)成功解决.
在这种情况下,新的编译器是新bug的潜在来源.
另一方面,较新的编译器带有额外的工具:
使用消毒剂(Address Sanitizer,Memory Sanitizer或Undefined Behavior Sanitizer)对二进制文件进行检测,然后对其进行模糊处理(例如使用American Fuzzy Lop)已经发现了许多高知名度软件中的漏洞,例如参见LWN.net这篇文章.
除非您升级编译器,否则您无法访问这些新工具和所有未来工具.
通过坚持一个功能不足的编译器,你可以把头放在沙子和交叉的手指上,没有发现任何漏洞.如果您的产品是高价值目标,我建议您重新考虑.
注意:即使您没有升级生产编译器,您也可能希望使用新的编译器来检查漏洞; 请注意,由于这些是不同的编译器,但保证会减少.
gna*_*729 46
您编译的代码包含可被利用的错误.这些错误来自三个来源:源代码中的错误,编译器和库中的错误,以及编译器变成错误的源代码中的未定义行为.(未定义的行为是一个错误,但不是已编译代码中的错误.例如,i = i ++;在C或C++中是一个错误,但在您编译的代码中,它可能会增加1,然后确定或设置我是一些垃圾,是一个错误).
由于测试和修复由于客户错误报告导致的错误,编译代码中的错误率可能很低.因此最初可能存在大量错误,但这已经下降了.
如果升级到较新的编译器,则可能会丢失编译器错误引入的错误.但是这些错误都会成为你所知道的没有人发现并且没有人被利用的错误.但是新编译器本身可能存在错误,而且重要的是,较新的编译器更倾向于将未定义的行为转换为编译代码中的错误.
所以你的编译代码中会有很多新bug; 黑客可以找到和利用的所有错误.除非你做了大量的测试,并且将代码留给客户以便长时间发现bug,否则它将不那么安全.
t0m*_*13b 19
如果它没有破坏,请不要修理它
你的老板说得对,但更重要的因素是保护输入,输出和缓冲区溢出.无论使用何种编译器,缺乏这些都是从这个角度来看链中最薄弱的环节.
但是,如果代码库是古老的,并且已经采取措施来缓解所使用的K&R C的弱点,例如缺乏类型安全性,不安全的fgets等,那么就要权衡" 将编译器升级到更现代化的C99"的问题/ C11标准打破了一切? "
前提是,有一条明确的路径可以迁移到更新的C标准,这可能会产生副作用,最好是尝试旧代码库的分支,评估它并进行额外的类型检查,完整性检查,并确定是否升级到较新的编译器对输入/输出数据集有任何影响.
然后你可以向你的老板展示," 这是更新的代码库,重构,更符合行业认可的C99/C11标准...... ".
这是必须权衡的赌博,非常谨慎,对改变的抵制可能会在那种环境中表现出来并且可能拒绝接触新的东西.
编辑
刚刚坐了几分钟,意识到这一点,K&R生成的代码可以在16位平台上运行,很有可能,升级到更现代的编译器实际上可能会破坏代码库,我在思考架构方面,会生成32位代码,这可能对用于输入/输出数据集的结构产生有趣的副作用,这是另一个需要仔细权衡的重要因素.
此外,由于OP提到使用Visual Studio 2008来构建代码库,使用gcc可能会导致MinGW或Cygwin进入环境,这可能会对环境产生影响,除非目标是针对Linux,那么它将是值得一试,可能要包括额外的开关到编译器,以尽量减少旧K&R代码库的噪音,另一个重要的是进行了大量的测试,以确保没有功能被打破,可能结果是一个痛苦的运动.
可以使用旧的C编译器破坏编译程序的安全性吗?
当然,如果旧编译器包含您知道会影响程序的已知错误,它可以.
问题是,是吗?要确切知道,您必须阅读从您的版本到当前日期的整个更改日志,并检查多年来修复的每个错误.
如果你没有找到会影响你的程序的编译器错误的证据,那么仅仅为了它而更新GCC似乎有点偏执.您必须记住,较新的版本可能包含尚未发现的新错误.最近在GCC 5和C11支持下做了很多改变.
话虽如此,80年代编写的代码很可能已经填满了安全漏洞并依赖于定义不明确的行为,无论编译器如何.我们在这里讨论的是标准前的C.
存在安全风险,恶意开发人员可能会通过编译器错误进入后门.根据正在使用的编译器中已知错误的数量,后门可能看起来或多或少不显眼(无论如何,关键是代码是正确的,即使在源级别进行了复杂处理.源代码审查和测试使用一个非错误的编译器将找不到后门,因为后门在这些条件下不存在).对于额外的拒绝点,恶意开发人员也可能自己查找以前未知的编译器错误.同样,伪装的质量将取决于所发现的编译器错误的选择.
这种攻击在程序须藤说明这篇文章.bcrypt为Javascript minifiers写了一篇很棒的后续文章.
除了这个问题,C编译器的进化一直利用未定义行为更多和更多和更积极,这是写在真诚地如此旧的C代码实际上更安全从时间一个C编译器来编译,或者编译-O0(但是在新版本的编译器中甚至在-O0中引入了一些新的破坏程序的UB漏洞利用优化).
小智 6
另一个需要担心的方面是开发新代码.
对于某些语言功能,较旧的编译器可能具有与程序员标准化和期望的不同的行为.这种不匹配会减慢开发速度并引入可被利用的细微错误.
较旧的编译器提供较少的功能(包括语言功能!),也不进行优化.程序员将破解这些缺陷 - 例如重新实现缺失的功能,或者编写模糊但运行速度更快的聪明代码 - 为创建微妙的错误创造新的机会.
原因很简单,旧的编译器可能有旧漏洞和漏洞,但新的编译器会有新的漏洞和漏洞利用.
您不是通过升级到新编译器来"修复"任何错误.您切换旧错误和漏洞利用新的漏洞和漏洞利用.
归档时间: |
|
查看次数: |
9128 次 |
最近记录: |