web-dev-qa-db-ja.com

古いCコンパイラを使用すると、セキュリティ上のリスクがありますか?

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

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

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

しかし、これらの古いものを使用するのが良い考えかどうかはわかりません。

私の質問は:

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

更新:

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

136
Calmarius

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

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

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

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

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

100
plugwash

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


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

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


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

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

サニタイザー(アドレスサニタイザー、メモリーサニタイザー、または未定義の動作サニタイザー)でバイナリをインストルメントし、ファジング( American Fuzzy Lop などを使用)すると、多くの有名なソフトウェアの脆弱性が明らかになります。例 LWN.netの記事

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

処理能力の低いコンパイラーにとどまることで、あなたは頭を砂の中に置き、脆弱性が見つからないという指を交差させています。製品が価値の高いターゲットである場合、再検討することをお勧めします。


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

52
Matthieu M.

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

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

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

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

46
gnasher729

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

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

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

ただし、副作用を引き起こす可能性のある新しいC標準に移行する明確な方法がある場合、古いコードベースの分岐を試み、それを評価し、追加の型チェック、健全性チェックを行い、新しいコンパイラは、入力/出力データセットに影響を与えます。

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

それが重くのしかかる賭けです、非常に慎重に変化への抵抗その環境でそこに表示される可能性があり、新しいものに触れることを拒否する場合があります。

編集

数分座って、これだけに気づき、K&Rで生成されたコードは16ビットプラットフォームで実行できる可能性があり、可能性としては、最新のコンパイラーにアップグレードすると実際にコードベースが壊れる可能性があり、アーキテクチャの観点から考えて、32ビットコードが生成される、これは入力/出力データセットに使用される構造に面白い副作用をもたらす可能性があります。これは別のhuge慎重に評価する要因です。

また、OPはVisual Studio 2008を使用してコードベースを構築することについて言及しているため、gccを使用すると、MinGWまたはCygwinのいずれかが環境に取り込まれ、ターゲットがLinuxでない限り、環境に影響を与える可能性があります試してみる価値がありますが、古いK&Rコードベースのノイズを最小限に抑えるためにコンパイラに追加のスイッチを含める必要があります。他の重要なことは、機能が破損しないことを確認するために多くのテストを実行することです。

19
t0mm13b

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

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

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

プログラムに影響するコンパイラのバグの証拠が見つからない場合、GCCを更新するためだけにGCCを更新するのは少し妄想的に思えます。新しいバージョンには、まだ発見されていない新しいバグが含まれている可能性があることに留意する必要があります。 GCC 5およびC11のサポートにより、最近多くの変更が行われました。

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

9
Lundin

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

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

この懸念とは別に、Cコンパイラの進化は未定義の動作 more および more および more を積極的に活用することでした。誠意を持って書かれたものは、実際にはその時点からCコンパイラでコンパイルされるか、-O0でコンパイルされます(ただし、一部の新しいプログラム破壊UBエクスプロイト最適化 -O0でもコンパイラの新しいバージョンで導入されます )。

9
Pascal Cuoq

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

7
DrMcCleod

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

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

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

6
Hurkyl

いや

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

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

5
coteyr

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

2
Anders

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

  • 明示的:「古いコンパイラを使用する場合、より大きなリスクがあります」(タイトルのように多かれ少なかれ)
  • 暗黙的:「管理者にアップグレードを説得する方法」

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

しかし、システムがハッカーにさらされていない場合は、おそらくコンパイラのアップグレードが有効性を高めるかどうかにもっと関心があるはずです。MSVS2013コード分析は、MSVS 2010よりもはるかに早く潜在的なバグを見つけ、C99/C11を多かれ少なかれサポートします–正式に実行されるかどうかはわかりませんが、宣言をステートメントの後に続けることができ、for- loopsで変数を宣言できます。

0
PJTraill