ルール
防止 共通 セグメンテーション フォールト パターン
ヌル ポインタ を参照しない、 バッファ オーバーフロー、
そして 後フリー使用 エラー 原因 クラッシュ そして セキュリティの脆弱性 脆弱性の原因となります。
対応言語 C/C++はじめに
セグメンテーションフォールトは、C/C++アプリケーションにおけるクラッシュおよびエクスプロイト可能な脆弱性の最も一般的な原因であり続けています。これらのメモリアクセス違反は、コードが所有していないメモリを読み書きしようとしたときに発生し、通常はヌルポインタの逆参照、バッファオーバーフロー、ダングリングポインタ、または解放済みメモリへのアクセスを通じて引き起こされます。単一のセグメンテーションフォールトが本番サーバーを停止させる可能性がありますが、さらに悪いことに、多くのセグメンテーションフォールトパターンは任意のコード実行にエクスプロイト可能です。
なぜ重要なのか
Security implications: バッファオーバーフローと解放後使用の脆弱性は、ほとんどのメモリ破損エクスプロイトの基盤です。攻撃者はこれらを悪用してリターンアドレスを上書きしたり、シェルコードを注入したり、プログラムの制御フローを操作したりします。2014年のHeartbleed脆弱性はバッファオーバーリードでした。現代のエクスプロイトも、攻撃者に直接メモリへのアクセスを提供するという理由から、依然としてこれらのパターンを標的としています。
システムの安定性: セグメンテーションフォールトは、アプリケーションを即座にクラッシュさせ、正常な劣化処理を行いません。本番システムでは、これはリクエストの破棄、トランザクションの中断、状態の破損を意味します。捕捉可能な高水準言語の例外とは異なり、セグフォールトはプロセスを終了させるため、再起動と復旧手順が必要となります。アタックサーフェスの拡大: 未チェックのポインタ逆参照ごとに、 strcpy, memcpy、または境界チェックなしの配列アクセスは、エクスプロイトの潜在的な侵入経路となります。攻撃者はこれらの脆弱性を連鎖させ、一方を利用してメモリを破壊し、もう一方のエクスプロイトを可能にします。
コード例
❌ 非準拠:
void process_user_data(const char* input) {
char buffer[64];
strcpy(buffer, input); // No bounds checking
char* token = strtok(buffer, ",");
while (token != NULL) {
process_token(token);
token = strtok(NULL, ",");
}
}
int* get_config_value(int key) {
int* value = (int*)malloc(sizeof(int));
*value = lookup_config(key);
return value; // Caller must free, but no documentation
}なぜそれが安全でないのか: 会社情報 strcpy() 入力が63バイトを超えると、この呼び出しはバッファオーバーフローを引き起こし、攻撃者がスタックメモリを上書きできるようになります。 get_config_value() この関数は呼び出しごとにメモリをリークし、他のコードがまだ参照している間に呼び出し元がメモリを解放すると、ダングリングポインタのリスクを生じさせます。
✅ 準拠済み:
void process_user_data(const char* input) {
if (!input) return;
size_t input_len = strlen(input);
char* buffer = malloc(input_len + 1);
if (!buffer) return;
strncpy(buffer, input, input_len);
buffer[input_len] = '\0';
char* token = strtok(buffer, ",");
while (token != NULL) {
process_token(token);
token = strtok(NULL, ",");
}
free(buffer);
}
int get_config_value(int key, int* out_value) {
if (!out_value) return -1;
*out_value = lookup_config(key);
return 0; // Caller owns out_value memory
}なぜそれが安全なのか: ヌルポインタチェックはデリファレンスによるクラッシュを防ぎます。動的割り当ては固定バッファサイズの制限を排除します。境界チェック付きコピーは strncpy() オーバーフローを防止します。明確な所有権セマンティクスは get_config_value() 呼び出し元がメモリを提供することで、割り当ての混乱やメモリリークを回避する箇所。
まとめ
CおよびC++におけるメモリ安全性は、すべてのポインタ操作とメモリ割り当てにおいて防御的プログラミングを必要とします。セグメンテーション違反は避けられないものではなく、一貫したNULLチェック、境界検証、および明確なメモリ所有権パターンによって防止できます。これらのパターンを本番環境投入前に検出することで、クラッシュとエクスプロイト可能な脆弱性の両方を防ぎます。

