6月15日、Jakub Beránek氏が「How memory safety CVEs differ between Rust and C/C++」と題した記事を公開した。この記事では、RustとC/C++におけるメモリ安全性関連のCVE(脆弱性報告)の扱われ方の本質的な違いについて詳しく紹介されている。以下に、その内容を紹介する。
CVE数の比較は誤解を招く
Rustの採用が進む中、「RustもCVEが報告されているならC/C++と変わらない」という批判が繰り返し登場する。しかしこの比較には重要な前提が欠けている。両言語ではメモリ安全性に関する潜在的脆弱性の報告基準が根本的に異なるのだ。
著者は世界で最も使われているC言語のネットワークライブラリcurlを例に、この違いを鮮やかに説明している。
curlで5行の「脆弱性」を作る実験
curlは1998年のリリース以来、長年にわたって開発され、非常に堅牢なライブラリとして知られている。著者はそのドキュメントから最初に見つけた関数curl_getenvを使い、次のような5行のプログラムを書いた。
#include <curl/curl.h>
int main(void) {
curl_getenv(NULL);
}
このプログラムはコンパイル時に警告なく通るが、実行するとセグメンテーション違反を起こす。これは明らかなメモリ安全性の問題だ。では、これをcurlの脆弱性として報告すべきだろうか?
答えはノーである。そしてこれは誰もが直感的に理解できる。しかし、なぜそう判断できるのだろうか?ここにRustとC/C++の違いを理解する鍵がある。
C/C++における「誤用」という概念
C/C++では、このような問題はライブラリの誤用として扱われ、ライブラリ側の問題とは見なされない。その理由は主に2つある。
契約を正確に記述できない:C言語の型システムでは、APIの前提条件や不変条件を正確に表現することが難しい。実際、
curl_getenvのドキュメントには「NULLを渡してはいけない」とは書かれていない。報告が実質不可能:C/C++では未定義動作(UB)を引き起こす方法が無数にあり、すべての潜在的な誤用を報告すれば、ほとんどのライブラリが数百万のCVEで埋め尽くされることになる。未定義動作とは、言語仕様が動作を規定していない状態のことで、メモリ破壊やクラッシュなど予測不可能な結果を引き起こす。
つまり、C/C++では「特定の誤用が実際に悪用された」場合にCVEを発行するが、「誤用可能なAPIの存在」自体はCVEとして扱わない。これは実務的な判断だが、潜在的な危険性は放置されたままだ。
Rustでの扱いはどう違うのか
Rustの人気HTTPライブラリhyperで同様の状況を考えてみる。次のようなコードを書いたとしよう。
fn main() {
hyper::foo(None);
}
このプログラムにunsafeブロックが含まれていないにもかかわらず、実行するとセグメンテーション違反が起きた場合、これは間違いなくhyperのCVEとなる。
Rustでは、**unsafeを使わずにメモリバグを引き起こせる状態そのものが脆弱性と見なされる。このようなAPIは「soundness hole(健全性の穴)」があると言われ、修正対象となる。言い換えれば、Rustでは実際の悪用例が見つかっていなくても、誤用可能性の存在だけでCVEが報告される**。
この基準をC言語に適用すれば、curl_getenvもCVEとして報告されるべきだが、C言語にはsafe/unsafeの概念がない(すべてが暗黙的にunsafe)ため、それは意味をなさない。
メモリ安全性が実践でスケールする理由
Rustでは「この関数を正しく使えているか?」という問いに対する答えが明確だ。
unsafeマークがない関数:答えは常に「YES」。誤用は不可能。unsafeマークがある関数:呼び出し側もunsafeブロックで囲む必要があり、コードレビューで潜在的危険箇所が一目で分かる。
前者がRustのメモリ安全性が実践的にスケールする理由だ。コードにunsafeを使わない限り(大半のケースで不要)、メモリ安全性の問題が発生してもそれはライブラリ側の責任であり、利用者側のコードには影響しない。
一方、curlのような堅牢なC言語ライブラリでも、それを使う数百万のプログラムが「持ち方を間違える」だけで簡単にメモリ不安全を引き起こし、curl開発者にはそれを防ぐ手段がない。これがGoogleのAndroidチームがRust導入後にメモリ安全性バグが劇的に減少した理由でもある。
業界における文脈
この議論の背景には、ソフトウェア業界全体でメモリ安全性への注目が高まっている現状がある。Microsoftはセキュリティバグの70%がメモリ安全性の問題と報告しており、GoogleのChromiumプロジェクトでも同様の傾向が確認されている。
こうした状況を受けて、米国政府のCISA(サイバーセキュリティ・インフラストラクチャセキュリティ庁)も2023年にメモリ安全な言語の採用を推奨する報告書を発表している。RustとC/C++のCVE報告基準の違いを理解することは、こうした業界動向を正しく解釈する上でも重要だ。
まとめ
著者は、RustとC/C++のCVE数を行数あたりで単純比較することは極めて誤解を招くと結論づけている。両言語では脆弱性の報告基準が本質的に異なるためだ。Rustでは潜在的な誤用可能性の存在がCVEとなるが、C/C++では実際の誤用や悪用がCVEとなる。
この違いを理解せずに数字だけで比較することは、メモリ安全性の本質的な差異を見落とすことになる。Rustの価値は「CVEが少ない」ことではなく、「CVEになりうる状況を言語設計で根本から排除している」ことにある。
詳細はHow memory safety CVEs differ between Rust and C/C++を参照していただきたい。