static-analysis について
セキュリティ研究者や LLVM ユーザー向けの静的プログラム解析スキルです。データフロー、ポインター解析、汚染追跡、プログラムスライシングを扱い、脆弱性検出やコード品質評価に使う解析ツールも紹介します。
主な機能
- 01データフローと制御フロー解析
- 02ポインターとエイリアス解析
- 03汚染と情報フローの追跡
- 04プログラムスライシングと依存グラフ
- 05LLVM 解析 API とフレームワーク
活用シーン
- 01定義から使用箇所までの値を追跡
- 02ポインターのエイリアス候補を特定
- 03汚染データが危険な出力先に届くか検出
- 04コードのセキュリティ脆弱性を調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ gmh5225/ awesome-llvm-security --skill static-analysisインストール後、Claude Code で/static-analysisを入力して読み込まれたか確認します。
詳細
静的解析スキル
このスキルでは、セキュリティ研究、脆弱性検出、コード品質の評価に用いる、LLVM インフラストラクチャを使用した静的プログラム解析の手法を扱います。
解析カテゴリ
データフロー解析
- 前方解析:定義から使用箇所まで値を追跡します
- 後方解析:使用箇所から定義まで遡って追跡します
- May/Must 解析:保守的な近似と精密な近似
制御フロー解析
- ドミネーターツリー:コードの支配関係を特定します
- ポストドミネーターツリー:制御依存関係を解析します
- ループ解析:ループを検出し、その特性を明らかにします
ポインター解析
- フロー非依存:Andersen のアルゴリズム、Steensgaard のアルゴリズム
- フロー依存:プログラムの各地点におけるポインター値を追跡します
- コンテキスト依存:呼び出しコンテキストを区別します
LLVM 解析インフラストラクチャ
組み込み解析の使用
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/DominatorTree.h"
void analyze(llvm::Function& F, llvm::FunctionAnalysisManager& FAM) {
// Get dominator tree
auto& DT = FAM.getResult<llvm::DominatorTreeAnalysis>(F);
// Get loop info
auto& LI = FAM.getResult<llvm::LoopAnalysis>(F);
// Get alias analysis
auto& AA = FAM.getResult<llvm::AAManager>(F);
// Check if two pointers may alias
llvm::AliasResult AR = AA.alias(Ptr1, Ptr2);
}
カスタム解析の実装
class TaintAnalysis {
std::set<llvm::Value*> taintedValues;
public:
void markTainted(llvm::Value* V) {
taintedValues.insert(V);
}
bool isTainted(llvm::Value* V) {
return taintedValues.count(V) > 0;
}
void propagate(llvm::Instruction* I) {
// Propagate taint through operations
for (auto& Op : I->operands()) {
if (isTainted(Op)) {
markTainted(I);
break;
}
}
}
};
汚染解析
ソース・シンクモデル
// Define taint sources (user input, network, files)
bool isTaintSource(llvm::CallInst* CI) {
llvm::Function* F = CI->getCalledFunction();
if (!F) return false;
static const std::set<std::string> sources = {
"read", "recv", "fread", "getenv", "gets", "scanf"
};
return sources.count(F->getName().str()) > 0;
}
// Define sensitive sinks (SQL queries, system calls, format strings)
bool isSensitiveSink(llvm::CallInst* CI) {
llvm::Function* F = CI->getCalledFunction();
if (!F) return false;
static const std::set<std::string> sinks = {
"system", "exec", "printf", "strcpy", "memcpy", "sql_query"
};
return sinks.count(F->getName().str()) > 0;
}
手続き間解析
- 関数の境界を越えて汚染を追跡します
- コールグラフ解析により間接呼び出しを処理します
- 精度を高めるためにコンテキスト依存性を使用します
ポインター解析フレームワーク
Andersen の解析の使用
#include "llvm/Analysis/CFLAndersAliasAnalysis.h"
// Check may-alias relationship
void checkAlias(llvm::AAResults& AA, llvm::Value* P1, llvm::Value* P2) {
switch (AA.alias(P1, P2)) {
case llvm::AliasResult::NoAlias:
// Definitely don't alias
break;
case llvm::AliasResult::MayAlias:
// Might alias
break;
case llvm::AliasResult::MustAlias:
// Always alias
break;
}
}
ポイント・トゥ・セット
// Track what each pointer may point to
class PointsToAnalysis {
std::map<llvm::Value*, std::set<llvm::Value*>> pointsTo;
public:
void addPointsTo(llvm::Value* ptr, llvm::Value* target) {
pointsTo[ptr].insert(target);
}
const std::set<llvm::Value*>& getPointsTo(llvm::Value* ptr) {
return pointsTo[ptr];
}
};
依存関係解析
データ依存グラフ(DDG)
#include "llvm/Analysis/DDG.h"
void buildDDG(llvm::Function& F, llvm::FunctionAnalysisManager& FAM) {
auto& LI = FAM.getResult<llvm::LoopAnalysis>(F);
for (auto* L : LI) {
llvm::DataDependenceGraph DDG(*L, FAM.getResult<llvm::AAManager>(F));
for (auto& Node : DDG) {
// Analyze data dependencies in loop
}
}
}
プログラムスライシング
- 前方スライシング:変数の影響を受けるすべての文を見つけます
- 後方スライシング:変数に影響を与えるすべての文を見つけます
- デバッグ、テスト、セキュリティ解析に使用します
主な静的解析ツール
包括的なフレームワーク
- Phasar:産業用途に対応する LLVM ベースの解析フレームワーク
- SVF:スケーラブルなポインター解析および値フロー解析
- Joern:グラフクエリに対応したコード解析プラットフォーム
- CodeChecker:Clang ベースの静的解析統合ツール
特化型ツール
- clam:抽象解釈フレームワーク
- dg:依存グラフ構築ツール
- Semgrep:パターンベースの多言語解析ツール
セキュリティ解析の用途
脆弱性検出
// Buffer overflow detection
void checkBufferAccess(llvm::GetElementPtrInst* GEP) {
// Get array size if available
llvm::Type* SourceType = GEP->getSourceElementType();
if (auto* AT = llvm::dyn_cast<llvm::ArrayType>(SourceType)) {
uint64_t arraySize = AT->getNumElements();
// Check if index might exceed bounds
llvm::Value* Index = GEP->getOperand(2);
// Perform range analysis on index
}
}
解放後使用の検出
- メモリの割り当て・解放地点を追跡します
- ポインターの到達定義を構築します
- 解放呼び出し後の使用を警告します
情報フロー
- 機密データ(パスワード、鍵、PII)を追跡します
- ログ、ネットワーク、または信頼できないシンクへの漏えいを検出します
- 機密解除ルールを実装します
ベストプラクティス
- 健全性と完全性:トレードオフを理解します
- スケーラビリティ:大規模なコードベースではサマリーを使用します
- パス依存性:精度とパフォーマンスのバランスを取ります
- 誤検知の管理:対処可能な検出結果を優先します
- 増分解析:結果をキャッシュし、再解析を高速化します
IDE との統合
Clangd/LSP との統合
- リアルタイムの解析フィードバックを提供します
- エディターの診断機能と統合します
- クイックフィックスの提案に対応します
CI/CD との統合
- プルリクエストで解析を実行します
- 重大な検出結果がある場合はマージをブロックします
- 時間の経過に伴う解析傾向を追跡します
リソース
ツール一覧と研究資料を幅広く確認するには、README.md の Static Analysis セクションと Clang Plugins セクションをご覧ください。
詳細情報の取得
詳細かつ最新のリソースリンク、ツール一覧、プロジェクト資料が必要な場合は、次の場所から最新データを取得してください。
https://raw.githubusercontent.com/gmh5225/awesome-llvm-security/refs/heads/main/README.md
この README には、以下の厳選されたリストが幅広く掲載されています。
- 静的解析フレームワーク(Static Analysis セクション)
- ポインター解析および汚染追跡ツール
- プログラム検証およびバグ検出ツール
- Clang ベースのコード解析プラグイン
コメント
Markdown 対応