ブログ | CTO オフィス

C を超えて

何十年もの間、C とその直系の子孫は、システム プログラミングに選ばれるプログラミング言語でした。 1970 年代初頭に C が開発されたとき、それはアセンブリ言語からの重要な前進でした。 50年経った今、私たちはもっと良いことができるはずです。

1970 年、そしてその後も長年にわたり、コンピュータ セキュリティはほとんどの人々の関心の対象ではありませんでした。 インターネットにおける最初の重大なセキュリティ脆弱性は、それから何年も経った 1988 年に発生しました。 これはインターネット ワームとして知られ、メモリ内の配列が境界外でインデックス付けされるバッファ オーバーフローを利用します。  

C++ を含む C 言語ファミリでは、配列の境界チェックは行われません。 配列が正しくアクセスされるようにするのはプログラマーの責任です。 したがって、バッファ オーバーフロー エラーはよく発生します。 さらに悪いことに、バッファ オーバーフローを意図的に発生させ、アクセスすべきでないメモリにアクセスすることも容易です。

バッファオーバーフローは、メモリの安全性の欠如の一例にすぎません。 その他の関連する例としては、ポインタ演算やダングリングポインタ(別名、解放後使用バグ)などがあります。 今日では、さまざまな技術を採用して、それらの言語で書かれたプログラムにメモリ安全性の問題がないことを保証するプログラミング言語が数多くあります。 C ファミリーの言語ではそのような保証はありません。メモリの安全性はこれらの言語の設計目標ではありませんでした。

セキュリティ脆弱性の約 70% は、メモリ安全性の違反が原因です。 この主張は圧倒的なデータによって裏付けられています。 メモリの安全性は次の点を考慮します。

  • 悪用された脆弱性の 67% が実際に公開され、検出されています ( Google Project Zero 2021の推定による)。
  • Android の脆弱性の 90% ( Google による)。 この数値は最近は減少傾向にありますが、Rust の使用により、リモートで悪用可能な脆弱性の 89% は依然としてメモリの安全性に関連しています。
  • Microsoft の脆弱性の 70% (Microsoft による)。
  • 最近の Apple の脆弱性修正の大部分 ( CatalinaBig SurMontereySafariiOStvOSwatchOS全体)。

2022 年 7 月、 Chrome 103.0.5060.134 で修正された脆弱性の 5/6 はメモリ安全性の問題でした。 明らかに、メモリ安全性のバグを排除することは非常に役立つでしょう。 業界では、メモリに安全なプログラミング言語を使用するという方法が長年知られていました。 歴史的に、問題は常にパフォーマンスの面での関連コストでした。 メモリの安全性は重要であるため、従来のオーバーヘッドなしでメモリの安全性を実現するための新しい戦略に取り組んできました。 現在、実行時のコストをほとんどまたはまったくかけずにメモリ安全性エラーを排除する方法がわかっています。 Rust などの言語では、型システム設計の革新を利用して、コストのかかるランタイム サポートなしでメモリの安全性を保証します。

これは避けられない結論につながります。C/C++ (またはより一般的には、メモリが安全でない言語) で新しいシステム コードを書くのをやめましょう。

これは、既存のコードを大規模かつ無差別に書き直すことを求めるものではありません。 既存のソフトウェアを置き換えるにはコストがかかり、リスクがないわけではありません。 しかし、業界は、既存のコードベースにメモリ安全でないコードを追加することで問題を悪化させることをやめなければなりません。 既存のコードについては、信頼できないユーザー入力の検証や使用を担当するコンポーネント、特権コンテキストで実行されるコンポーネント、サンドボックス外で実行されるコンポーネントなど、最も機密性の高いコンポーネントの書き換えを優先します。

この立場は広く支持されているものの、一部の人々にとっては依然として議論の余地がある。 ここでは、現状維持を支持する一般的な議論と、それに対する私たちの反応をいくつか紹介します。

  • バグはプログラミング言語に特有のものではありません。  
    • ほとんどの脆弱性はメモリ安全性のバグによって発生します。 Rust などのメモリセーフ言語では、メモリセーフティバグは発生しません。 したがって、メモリセーフ言語を使用すると、ほとんどの脆弱性が最初から作成されるのを防ぐことができます。
  • コードレビューによりバグが発見されます。
    • 調査によると、コード レビューによって状況は改善されるものの、多くの問題が見逃されることが多く、すべてを見つけられるわけではないことが分かっています。
  • 安全でないモジュールがあると、全体のポイントが意味をなさなくなります。
    • 安全でないコードはコードの非常に小さなセクションで明示的に区切られるため、その検証にリソースを集中させることができます。
  • メモリセーフ言語の実装にはバグがある可能性があります。
    • 確かにそうですが、その確率ははるかに低いです。 コンパイラは比較的小さく、厳密にテストされています。 また、コンパイラを修正すると、単一のプログラムのバグを修正するのではなく、そのコンパイラでコンパイルされたすべてのプログラムが自動的に修正されます。
  • このような間違いを犯すのは、初心者または無能なプログラマーだけです。
    • それどころか、上記のデータは、Chrome ブラウザや Windows および MacOS オペレーティング システムなどの主要なシステム プロジェクトから取得されたものです。 これらのプロジェクトには、業界で最も有能で経験豊富な開発者が揃っていますが、それでもメモリの安全性に関する問題が残っています。
  • これらの問題はベストプラクティスに従うことで回避できます。
    • 上記を参照してください。 言及したチームは非常に厳格なプラクティスに従い、利用可能な最高のツールを使用しています。
  • すべてのコードを書き直すのは非現実的です。
    • すべてのコードを完全に書き直すことを主張している人はいません。 むしろ、重要な要素 (高い権限、大きな攻撃対象領域、セキュリティ保証の中心) に重点を置き、メモリセーフな言語で新しいコードを記述するアプローチが推奨されます。
  • パフォーマンスが不十分です。
    • Rust のパフォーマンスは C/C++ とほぼ同等です。 わずかな違いはセキュリティ上のリスクを正当化するものではありません。 Rust プログラムの方が高速になる状況もあります。
  • Rust のようなメモリセーフなシステムプログラミング言語はまだ新しいです。
  • 静的分析、ファジング、サンドボックス化などの他のソリューションもあります。

メモリの安全性の低さとそれに対する反応の定量化を参照してください 上記の点に関する詳細な議論については、こちらをご覧ください。

反対意見があるにもかかわらず、必要な変化を求める勢いは高まっています。 たとえば、Linux Foundation が支援するOpen Source Software Security Foundationには多額の投資が行われています。 メモリの安全性は米国で議論されている 上院の報告書とNSAによる。 Consumer Reports はまた、企業や政府機関に一連の推奨事項を提示することで、この動きを加速させる可能性のあるさまざまなインセンティブを特定することにも取り組んでいます。

要約すると:

過去 50 年間で、社会におけるコンピューティングの重要性は飛躍的に高まりました。 私たちのコンピューティング インフラストラクチャに対する脅威の状況も、ここ数十年で劇的に変化しました。 しかし、コンピューティング システムの構築に使用するプログラミング言語は、それに応じて変化していません。 メモリの安全性の欠如は、ソフトウェアにおけるセキュリティ脆弱性の最大の原因です。 これは特定の種類のソフトウェアに特有のことではなく、メモリが安全でない言語が使用されている場所ではどこでも、メモリの安全性に関する問題が多発しています。 そして、数字で見ると、他のどの脆弱性もこれに匹敵しません。

私たちは今、この深刻化する問題に対処する手段を持っており、業界としてそれを実行することが極めて重要です。 幸いにも、状況の認識は広まりつつありますが、問題は緊急であり、一刻の猶予もありません。