古いCコンパイラの使用はセキュリティリスクですか?


139

私たちには、誰も気にしないいくつかのビルドシステムが本番環境にあり、これらのマシンはGCC 3やGCC 2のようなGCCの古いバージョンを実行しています。

そして私はそれをより新しいものにアップグレードするよう経営陣を説得することはできません:彼らは「壊れていなければそれを修正しないでください」と言います。

私たちは非常に古いコードベース(80年代に書かれた)を維持しているため、このC89コードはこれらのコンパイラーで問題なくコンパイルされます。

しかし、私はこれらの古いものを使うのが良い考えだとは思いません。

私の質問は:

古いCコンパイラを使用すると、コンパイルされたプログラムのセキュリティが低下する可能性がありますか?

更新:

同じコードがVisual Studio 2008 for Windowsターゲットによってビルドされ、MSVCはまだC99またはC11をサポートしていません(新しいMSVCがサポートしているかどうかはわかりません)。最新のGCCを使用してLinuxボックスでビルドできます。したがって、新しいGCCをドロップするだけで、おそらく以前と同じように正常にビルドされます。


5
興味深い質問-これは同様に価値が迅速に読み取ることがあります- developers.slashdot.org/story/13/10/29/2150211/... ..ので、新しいコンパイラは妥協セキュリティも可能性があります最適化します。
Neil

6
これらの古いgccバージョンは、ASLRのPIC / PIEへのコンパイルをサポートしていますか?彼らはスタックカナリアをサポートしていますか?W ^ X(NX)?そうでない場合は、脆弱性の緩和策がないため、アップグレードする十分な理由があります。
EOF 2016年

12
gcc 4.xからの警告を見るだけで、自分が知らなかった既存のセキュリティホールの負荷全体が即座に明らかになる場合があります。
OrangeDog 2016年

7
@OrangeDog:なぜgcc 4.xなのですか?gcc6は現在のリリースシリーズであり、gcc 5はしばらくの間使用されています。しかし、そうです、-O3 -Wall -Wextra -fsanitize=undefined最新のgccとclangで特定された問題を修正することが役立つはずです。
Peter Cordes、2016年

4
@OrangeDog GCCはマーケティングバージョン番号に移行しました。GCC 5は、デフォルトのCおよびC ++標準とlibstdc ++ ABIを変更したため、メジャーバージョンのバンプに値しました。GCC 6は5.1と呼ばれるべきでした。
zwol

回答:


102

実際、私は反対を主張します。

C標準では動作が定義されていないが、特定のプラットフォームの「ダムコンパイラ」で何が起こるかは明らかな場合がいくつかあります。符号付き整数をオーバーフローさせたり、2つの異なる型の変数を介して同じメモリにアクセスしたりするような場合。

最近のバージョンのgcc(およびclang)では、これらのケースが、「未定義の動作」条件でのバイナリの動作を変更しても、最適化の機会として扱われ始めています。コードベースがCを「ポータブルアセンブラ」のように扱った人々によって作成された場合、これは非常に悪いことです。時間が経つにつれ、オプティマイザーはこれらの最適化を実行する際にコードのますます大きなチャンクを検討し始め、バイナリーが「ダムコンパイラーによってビルドされたバイナリー」が行うこと以外のことを実行する可能性が高まります。

「従来の」動作を復元するコンパイラスイッチ(上記の2つの場合の-fwrapvおよび-fno-strict-aliasing)がありますが、最初にそれらについて知る必要があります。

原則として、コンパイラのバグにより、準拠コードがセキュリティホールに変わる可能性がありますが、私はこれのリスクは大規模なスキームでは無視できると考えます。


13
しかし、この議論は両方の方法で機能します。コンパイラは、予測可能な「未定義の動作」を持っている場合、それはそれの悪用を作るために間違いなく、より簡単にすることができます...
アンドレ・

18
@Andre コンパイルされたコードは、とにかく予測できない未定義の動作をします。つまり、コードがコンパイルされると、その特定のコンパイル済みバージョンでは、予測できない動作が予測可能になります。
user253751 2016年

6
people who treated C like a "portable assembler"Cってなんだろう?
最大

10
@Maxこの回答は、最新のオプティマイザが原因で、「ポータブルアセンブラ」の概念が実際には少なくとも時代遅れであることを正確に警告しています。そして、そもそもそれが概念的に正しいことは決してなかったと私は主張します。
Theodoros Chatzigiannakis

6
未定義の振る舞いに依存し、後に彼らが蒔いたものを刈り取り始める人々のために、ここで同情はありません。これは、新しいコンパイラが本質的に安全性が低いことを意味するのではありません。つまり、非準拠のコードが時限爆弾だったことを意味します。非難はそれに応じて配分されるべきです。
underscore_d

52

両方の行動方針にはリスクがあります。


古いコンパイラーには成熟度の利点があり、それらで壊れたものはおそらく(ただし、保証はありません)正常に回避されています。

この場合、新しいコンパイラは新しいバグの潜在的な原因です。


一方、新しいコンパイラには追加のツールが付属しています。

  • GCCとClangはどちらも、さまざまな種類の未定義の動作を検出するためにランタイムを計測できるサニタイザーを備えています(GoogleコンパイラチームのChandler Carruthは、昨年、完全なカバレッジに達したと期待していると主張しました)
  • Clangは少なくとも強化機能を備えています。たとえば、制御フローの整合性制御フローのハイジャックを検出することです。また、スタックスマッシング攻撃から保護するための強化実装もあります(スタックの制御フロー部分をデータ部分から分離することにより) ; 強化機能は一般的にオーバーヘッドが低い(CPUオーバーヘッドが1%未満)
  • Clang / LLVMはlibFuzzerにも取り組んでいます。これは、テスト中の関数の入力スペースをスマートに探査するインストゥルメント化されたファジングユニットテストを作成するツールです(まだ探査されていない実行パスを取得するために入力を微調整することにより)

バイナリをサニタイザー(アドレスサニタイザー、メモリサニタイザー、または未定義の動作サニタイザー)で計測してファジングすると(たとえば、アメリカのファジーロップを使用して)、多くの注目を集めているソフトウェアの脆弱性が発見されました。たとえば、このLWN.netの記事を参照してください

これらの新しいツール、および将来のすべてのツールは、コンパイラーをアップグレードしない限りアクセスできません。

パワー不足のコンパイラーにとどまることで、脆弱性が発見されない砂浜に頭を抱え、指を交差させています。あなたの製品が価値の高いターゲットである場合、私はあなたに再考することをお勧めします。


注:実動コンパイラーをアップグレードしない場合でも、とにかく新しいコンパイラーを使用して脆弱性をチェックすることをお勧めします。ただし、これらは異なるコンパイラであるため、保証は少なくなります。


1
+1は、他の答えの「b-but my good old UB」バンドワゴンを積み上げるよりも、新しいコンパイラの方がより安全である場合があることに言及するのを煩わしく思います。これは、セキュリティに直接関連しない他の多くの改善点に加えて、合理的な現代化をさらに推進するものです。
underscore_d

「あいまいさによるセキュリティ」を提唱するような気がしますが、古いコンパイラに影響するバグは既知であり、公開されています。新しいコンパイラがバグを導入することに同意しますが、これらのバグは以前のバージョンのようにまだ公開されていません。これは、アプリケーションを頻繁に更新する場合のセキュリティです。
The6P4C 2016年

チャンドラー・カーラスはとてもかわいい、そしてそのような素晴らしいことを語っています。できれば彼と結婚したい。
Daniel Kamil Kozar、2016年

46

コンパイルされたコードには、悪用される可能性のあるバグが含まれています。バグは3つのソースから発生します。ソースコードのバグ、コンパイラとライブラリのバグ、およびコンパイラがバグに変換するソースコードの未定義の動作です。(未定義の動作はバグですが、コンパイル済みコードのバグではありません。例として、i = i ++; CまたはC ++ではバグですが、コンパイル済みコードでは、iが1増加し、OKまたは設定される場合があります私はいくつかのジャンクになり、バグになります)。

コンパイルされたコードのバグの発生率は、テストと顧客のバグレポートによるバグの修正により、おそらく低くなっています。したがって、最初は多数のバグがあった可能性がありますが、それは減少しました。

新しいコンパイラにアップグレードすると、コンパイラのバグによって導入されたバグが失われる可能性があります。しかし、これらのバグはすべて、あなたの知る限り誰も発見せず、誰も利用していないバグです。しかし、新しいコンパイラー自体にバグがある可能性があり、重要なことに、新しいコンパイラーは未定義の動作をコンパイル済みコードのバグに変える傾向が強いです。

したがって、コンパイルされたコードには多くの新しいバグが含まれます。ハッカーが見つけて悪用できるすべてのバグ。そして、多くのテストを行い、コードを顧客に残してバグを長期間見つけさせない限り、安全性は低下します。


6
つまり、言い換えると、コンパイラーがどのような問題を引き起こすのかを簡単に判別する方法はありません。切り替えるだけで、不明な問題の別のセットを取得できますか?
Jeremy Kato

1
@JeremyKato:まあ、あなたがしている場合がありますまた、既知の問題の異なるセットを取得するには。コンパイラ自体に既知のセキュリティ上の欠陥があるかどうかはわかりませんが、具体的な例として、新しいコンパイラに更新すると、最新のlibcを取得できることを意味します(古いものを使用しているときに、これを行うには)、次に、この欠陥を修正していることがわかりますgetaddrinfo()access.redhat.com/articles/2161461。この例は、実際にはコンパイラのセキュリティ上の欠陥ではありませんが、10年以上にわたって、いくつかの既知の修正された欠陥が存在することになっています。
スティーブジェソップ2016年

2
ええ、実際にはその欠陥は2008年に導入されただけなので、質問者はそれから安全かもしれません。しかし、私のポイントはその特定の例についてではありません。古いツールチェーンがコードに追加する既知のバグが存在するということです。したがって、更新するときに、未知の未知数の新しいセットを導入することは事実ですが、それだけではありません。基本的には、最新のツールチェーンが修正する既知の重大な欠陥を残して「より安全」であるか、または独自のコードのすべての未定義の動作で再度サイコロを振るという未知の結果を取るかどうかを推測する必要があります。
スティーブジェソップ

19

壊れていない場合は修正しないでください

あなたの上司はこれを正しいと言っていますが、より重要な要素は、入力、出力、バッファオーバーフローの保護です。それらの欠如は、使用されるコンパイラーに関係なく、常にその観点からチェーンの最も弱いリンクです。

ただし、コードベースが古く、型の安全性の欠如、安全でないfgetsなど、使用されているK&R Cの弱点を軽減するための作業が行われた場合、「コンパイラーをより最新のC99にアップグレードするか/ C11標準はすべてを壊しますか?

副作用を引き起こす可能性がある新しいC標準に移行する明確なパスがあることを条件として、古いコードベースのフォークを試み、それを評価して、追加の型チェック、サニティチェックを行い、アップグレードするかどうかを決定するのが最善です。新しいコンパイラは、入力/出力データセットに影響を与えます。

次に、上司にそれを示すことができます。「これは、業界で認められているC99 / C11標準に沿った、より新しいリファクタリングされたコードベースです...」です。

それは、上に計量しなければならないギャンブルだ非常に慎重に変化にresistenceは、その環境であっ表示されることがありますし、新しいものに触れることを拒否することがあります。

編集

K&Rで生成されたコードは16ビットプラットフォームで実行できる可能性があり、K&Rで生成されたコードは実際にコードベースを壊す可能性があります。アーキテクチャの観点から考えると、32ビットコードが生成されます。 、これは、入出力データセットに使用される構造に面白い副作用をもたらす可能性があります。これは、慎重に検討する必要があるもう1つの大きな要因です。

また、OPはVisual Studio 2008を使用してコードベースを構築することを述べているため、gccを使用するとMinGWまたはCygwinのいずれかが環境に導入され、環境に影響を与える可能性があります。ただし、ターゲットがLinuxの場合を除き、ショットの価値があります。古いK&Rコードベースのノイズを最小限に抑えるためにコンパイラへの追加のスイッチを含める必要がある場合があります。他の重要なことは、機能が壊れていないことを確認するために多くのテストを実行することです。


同じコードがVisual Studio 2008 for Windowsターゲットによってビルドされ、MSVCはまだC99またはC11をサポートしていません(新しいMSVCがサポートしているかどうかはわかりません)。最新のGCCを使用してLinuxボックスでビルドできます。そのため、新しいGCCを導入するだけで、以前と同じように問題なく構築できます。
Calmarius、2016年

@Calmariusの頭に感謝します。質問を編集してコメントを含めるのが最善かもしれません。それは重要です:)そして、そこにあったはずです; D
t0mm13b

@Calmariusが私の回答を編集しました。これは、新しく更新された質問に対する私の考えです。
t0mm13b 2016年

2
「16ビットプラットフォームで実行している可能性があります。最新のコンパイラにアップグレードすると、実際にコードベースが機能しなくなる可能性があり、アーキテクチャ、32ビットコードの観点から考えています」新しい実装定義のコードにコードを移植することについての質問ではないと思いますパラメーター。
Pascal Cuoq 2016年

同意した。それはだ可能ランタイムの脆弱性は、コンパイラのバグにより作成することができました。しかし、バッファやスタックのオーバーランなどが原因で、コードにランタイムの脆弱性が含まれている可能性はるかに高くなります。したがって、このコードベースをより安全にするために時間を費やすときは、入力文字列の長さをチェックしてプログラムの制限を超えないようにするなどの作業に費やす必要があります。新しいコンパイラーを入手してもあまり役に立ちません。ネイティブ文字列と配列オブジェクトを使用する言語でコードを最初から書き直すと、非常に役立ちます。しかし、あなたの上司はその代金を払うことはありません。
O.ジョーンズ

9

古いCコンパイラを使用すると、コンパイルされたプログラムのセキュリティが低下する可能性がありますか?

もちろん、古いコンパイラに既知のバグが含まれていて、プログラムに影響を与えることがわかっている場合は可能です。

問題は、それですか?確実に知るには、バージョンから現在の日付までの変更ログ全体を読み、長年にわたって修正されたすべてのバグを確認する必要があります。

プログラムに影響を与えるコンパイラのバグの証拠が見つからない場合、GCCを更新することは、それがちょっと偏執的であるように思われます。新しいバージョンには、まだ発見されていない新しいバグが含まれている可能性があることに注意してください。GCC 5とC11のサポートにより、最近多くの変更が行われました。

そうは言っても、80年代に記述されたコードは、コンパイラに関係なく、セキュリティホールと不十分に定義された動作への依存ですでにいっぱいになっている可能性が高いです。ここでは、先行標準のCについて話しています。


6
私はそれがパラノイアだとは思わない。OPは上司を説得する理由を発明しようとしていると思います。おそらくOPは新しいコンパイラーを必要としています。なぜなら、それらはより良いasm(LTOによるファイル間最適化を含む)を作成し、より有用な診断/警告を備え、最新の言語機能と構文を許可するからです。(例:C11 stdatomic)。
Peter Cordes、2016年

9

悪意のある開発者がコンパイラのバグを介してバックドアをこっそり侵入できるというセキュリティ上のリスクがあります。使用中のコンパイラの既知のバグの量によっては、バックドアが目立たないように見える場合があります(いずれにしても、ポイントは、コードが複雑であっても、ソースレベルで正しいということです。ソースコードのレビューとテストバグのないコンパイラは、これらの条件ではバックドアが存在しないため、バックドアを検出しません。追加の否認可能性ポイントについては、悪意のある開発者は、以前に知られていないコンパイラのバグを自分で探すこともあります。この場合も、カモフラージュの品質は、見つかったコンパイラバグの選択によって異なります。

この攻撃は、この記事のプログラムsudoで説明されています。bcryptはJavascript minifiersのすばらしいフォローアップを書きました

別にこの懸念から、Cコンパイラの進化は未定義の動作を活用することであった以上多くの、より積極的に、誠実に書かれていたので、古いCコードは、実際にはより多くの時間から、Cコンパイラでコンパイル、またはでコンパイルされ、安全なことになります-O0(ただし、新しいバージョンのコンパイラーでは、-O0でも、プログラムを壊すUBを悪用する最適化がいくつか導入されています)。


7

古いコンパイラには、既知のハッキング攻撃に対する保護機能がない場合があります。たとえば、スタック破壊保護はGCC 4.1まで導入されませんでした。つまり、古いコンパイラでコンパイルされたコードは、新しいコンパイラが保護する方法で脆弱になる可能性があります。


6

心配するもう1つの側面は、新しいコードの開発です

古いコンパイラは、一部の言語機能について、プログラマが標準化および期待しているものとは異なる動作をする場合があります。この不一致により、開発が遅くなり、悪用可能な微妙なバグが発生する可能性があります。

古いコンパイラは提供する機能が少なく(言語機能を含む!)、最適化もされていません。プログラマーはこれらの欠陥を回避するためにハッキングします。たとえば、不足している機能を再実装したり、あいまいであるが高速に実行される巧妙なコードを記述したりして、微妙なバグを作成する新しい機会を作り出します。


5

いや

その理由は単純です。古いコンパイラには古いバグとエクスプロイトがあるかもしれませんが、新しいコンパイラには新しいバグとエクスプロイトがあります。

新しいコンパイラにアップグレードして、バグを「修正」しない。古いバグとエクスプロイトを新しいバグとエクスプロイトに切り替える。


3
これらは非常に単純化しているように見えます。新しいコンパイラーには弱点があるかもしれませんが、古いコンパイラーよりも脆弱であると私は予想します。
PJTraill

しかし、新しいコンパイラには未知の新しい弱点があるかもしれません。コンパイラだけでは、更新が必要なセキュリティリスクではありません。表面積を減らしていません。既知の問題のセットを未知のセットと交換します。
coteyr 2018

バグを見つけるのに役立つツールは、GCCの初期の頃から大幅に改善されており、これらのツール(静的分析、インストルメント済みコードの動的分析/サニタイザー、ファザーなど)もコンパイラーコードに適用され、品質の向上に役立っています。GCC 2時代のすべてのクラスのバグを見つけるのははるかに困難でした。バージョン間でのコンパイラのバグの比較-7ページを参照:cs.utah.edu/~regehr/papers/pldi11-preprint.pdf GCC 4.5およびLLVM 2.8(最新版)には、ファジングによるバグがほとんどありません。
ジェットスキーSタイプ

2

新しいコンパイラーを使用するのではなく、古いコンパイラーのバグがよく知られ、文書化されている可能性が高いので、それらのバグを回避してコーディングすることで、それらのバグを回避するためのアクションを実行できます。したがって、アップグレードの引数としては不十分です。私が作業しているのと同じ議論があります。組み込みソフトウェアのコードベースでGCC 4.6.1を使用します。新しい文書化されていないバグを恐れて、最新のコンパイラにアップグレードすることは(管理の中でも)非常に躊躇しています。


0

あなたの質問は2つの部分に分かれます:

  • 露骨な表現:「古いコンパイラを使用することでリスクが高まるか」(タイトルのように多少異なる)
  • 暗黙的:「経営陣にアップグレードを説得するにはどうすればよいですか」

おそらく、既存のコードベースで悪用可能な欠陥を見つけ、より新しいコンパイラがそれを検出したことを示すことで、両方に答えることができます。もちろん、あなたの経営陣は「古いコンパイラでそれを見つけた」と言うかもしれませんが、かなりの労力がかかることを指摘できます。または、新しいコンパイラーを介して実行して脆弱性を見つけ、それを悪用します(新しいコンパイラーでコードをコンパイルできる/許可されている場合)。友好的なハッカーの助けが必要かもしれませんが、それは彼らを信頼し、コードを表示できる(または新しいコンパイラを使用できる)かどうかに依存します。

ただし、システムがハッカーにさらされていない場合は、コンパイラのアップグレードによって効果が向上するかどうかにもっと関心を持つ必要があります。MSVS2013コード分析は、MSVS 2010よりもはるかに早く潜在的なバグを検出し、多かれ少なかれC99 / C11をサポートします–正式に実行されるかどうかは不明ですが、宣言はステートメントの後に続き、変数はfor-loopsで宣言できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.