Chapter 15
ソフトウェア防御と脆弱性管理
この章がなぜ必要なのか——CRA が要求するのは、まさにここだから.
04 章で見たとおり、セキュアブートは「正規に署名された脆弱なファームウェア」を 喜んで起動する。完全性は守っても、安全性は守らない。
そして 03 章で見たとおり、EU CRA は「既知の脆弱性なしで出荷すること」と 「サポート期間中の脆弱性対応」を法的義務にした。
つまり——脆弱性管理は、もはや技術的な良心ではなく、法的な要件である。
この章で使う既出の用語(定義は各リンク先). セキュアブート(02 章 3 節)、サポート期間中(03 章 2 節)、不可能(04 章 3 節)、完全性(06 章 6 節)、必要(09 章 6 節)、ベンダ提供(13 章 9 節)、最も危険(13 章 6 節)、CRA(14 章 6 節)、市場(14 章 5 節)、確実(14 章 6 節)、開発(14 章 5 節)
1. 組み込みで起きる脆弱性の型
メモリ安全性のバグ
C/C++ で書かれた組み込みソフトウェアの、最大の脆弱性源である。
| 型 | 内容 | 典型的な発生箇所 |
|---|---|---|
| バッファオーバーフロー | 配列の範囲外に書く | パケット解析、文字列処理 |
| 整数オーバーフロー | 長さ計算がオーバーフローして、小さいバッファに大きく書く | len = a + b; の後の malloc(len) |
| 符号の混同 | int と size_t の比較で負値が巨大な値になる | 長さチェック |
| Use-after-free | 解放後のポインタを使う | 動的確保がある場合 |
| オフバイワン | <= と < の間違い | ループ、境界チェック |
| フォーマット文字列 | printf(user_input) | ログ出力 |
| スタックオーバーフロー | 再帰、大きなローカル変数 | 深い呼び出し |
メモリ安全性の脆弱性を見る
コードパターンを選ぶと、何が起きるか、どの防御が効くかが表示される。
組み込みでは、PC より状況が悪い.
要因 内容 MMU がない プロセス分離がない。1 つの脆弱性で全メモリが触れる ASLR がない アドレスが固定なので、攻撃コードを書きやすい スタックとヒープが近い オーバーフローが他の重要データを踏む クラッシュが見えにくい 「たまに再起動する」で片付けられる W^X が徹底されていない RAM 上のデータを実行できてしまうことがある
代表的な攻撃対象
| 対象 | なぜ危険か |
|---|---|
| ネットワークスタック(TCP/IP) | 攻撃者が任意のパケットを送れる。認証前に処理される |
| BLE / Wi-Fi スタック | 同上。近接すれば誰でも送れる |
| パーサ全般(JSON、XML、Protobuf、画像、フォント) | 複雑な入力を扱う。バグが入りやすい |
| ブートローダの引数処理 | 起動時に外部入力を受ける |
| USB スタック | 物理的に接続されるだけで動く |
「認証前に処理されるコード」が最も危険である.
TLS ハンドシェイクの前、ペアリングの前、ログインの前に動くコードは、 誰からでも攻撃できる。ここに脆弱性があると、認証機構が意味をなさない。
- TCP/IP のパケット処理
- TLS ハンドシェイクの ClientHello / 証明書解析
- BLE のアドバタイズ・接続要求処理
- USB のディスクリプタ処理
この範囲のコードは、特に厳しくレビュー・テストすること。
2. 防御 — コンパイラとツールチェーン
まず、無料でできることを全部やる。
# GCC / Clang で必ず有効にすべきフラグ
-Wall -Wextra -Werror # 警告を全部出し、エラーにする
-Wformat=2 -Wformat-security # フォーマット文字列
-Wconversion -Wsign-conversion # 暗黙の型変換(組み込みでは重要)
-Wshadow # 変数の隠蔽
-fstack-protector-strong # スタックカナリア
-D_FORTIFY_SOURCE=2 # 標準関数の境界チェック(最適化と併用)
-fstack-usage # スタック使用量の静的解析
-fno-common # 暫定定義を禁止
# リンカ
-Wl,--gc-sections # 未使用コードの除去(攻撃面の削減)| 機能 | 効果 | 組み込みでの注意 |
|---|---|---|
| スタックカナリア | スタックオーバーフローを検出 | わずかな性能低下。乱数が要る(08 章) |
_FORTIFY_SOURCE | memcpy 等の境界チェック | サイズが静的に分かる場合のみ有効 |
| W^X(書き込みと実行の排他) | RAM 上のデータを実行させない | MPU で設定する(07 章) |
| ASLR | アドレスをランダム化 | 組み込みでは実質不可能なことが多い |
| CFI(制御フロー完全性) | 不正なジャンプを検出 | Armv8.1-M の BTI、PACBTI |
Armv8.1-M の PACBTI
Cortex-M85 / M55(一部)などが対応する、ハードウェアによる制御フロー保護。
| 機能 | 内容 |
|---|---|
| PAC (Pointer Authentication) | 戻りアドレスに署名(認証コード)を付ける。改ざんすると検出される |
| BTI (Branch Target Identification) | 間接分岐の飛び先が正当な landing pad かを検証する |
ROP(Return-Oriented Programming)攻撃への直接的な対策である.
ROP は「既存のコード断片を戻りアドレスの改ざんで繋いで、 任意の処理を実行する」攻撃で、W^X を回避できる。
PAC があると、戻りアドレスを書き換えても署名が合わないので検出される。 これは組み込みにとって大きな進歩である。
Cortex-A では Armv8.3-A から PAC、Armv8.5-A から BTI と MTE (Memory Tagging Extension、メモリ安全性のハードウェア支援)が使える。
3. 防御 — 言語とライブラリ
メモリ安全な言語
| 言語 | 組み込みでの状況 |
|---|---|
| Rust | 急速に普及中。no_std で組み込み可。Zephyr・embassy・RTIC などのエコシステム |
| Ada / SPARK | 航空宇宙・鉄道で実績。形式検証ができる |
| C++ (modern) | スマートポインタ・std::span などで安全性を上げられるが、C 互換部分が残る |
| MicroPython / Lua | 上位ロジック向け。実行環境自体は C |
Rust は「一部だけ置き換える」ことができる.
全部を書き直す必要はない。 最も危険な部分——パーサ、プロトコル処理——だけを Rust で書き、 C から呼ぶという段階的な移行ができる。
米国の CISA・NSA も「メモリ安全な言語への移行」を推奨する文書を出している。 新規開発では、少なくとも検討する価値がある。
コーディング規約
| 規約 | 用途 |
|---|---|
| MISRA C | 自動車・産業。安全性重視。静的解析ツールが対応 |
| CERT C | セキュリティ重視。CWE との対応が明確 |
| AUTOSAR C++14 | 自動車の C++ |
| BARR-C | 組み込み C の実務的な規約 |
MISRA C を「全部守る」のは現実的でないことが多い.
だが、セキュリティに直結する規則だけを選んで適用するのは有効である。
- 暗黙の型変換の禁止
- 動的メモリ確保の制限
- 再帰の禁止
- ポインタ演算の制限
CERT C のほうが、セキュリティ目的には直接的である。
4. テスト
| 手法 | 内容 | 効果 |
|---|---|---|
| 静的解析 (SAST) | ソースを解析してバグを見つける | 網羅的。誤検出も多い |
| 動的解析 (Sanitizer) | 実行時に検出(ASan / UBSan / MSan) | 強力。ホスト上でのテストに |
| ファジング | ランダム/変異させた入力を大量に投げる | プロトコル実装に極めて有効 |
| ペネトレーションテスト | 実機に対する攻撃 | 実際の脆弱性が見つかる |
| 形式検証 | 数学的に性質を証明する | 高コストだが確実 |
ファジングは組み込みでも有効
- プロトコル処理の関数を、ホスト(PC)でビルドできるように切り出す
- AFL++ / libFuzzer のハーネスを書く
- ASan / UBSan と組み合わせてビルドする
- 数時間〜数日走らせる
- クラッシュした入力を最小化して、バグを特定する
/* libFuzzer のハーネスの例 */
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
parse_protocol_packet(data, size); /* 実機と同じコードを呼ぶ */
return 0;
}「実機でしか動かない」を理由にテストを諦めないこと.
プロトコル解析、パケット処理、設定ファイルの読み込み—— これらはハードウェアに依存しないことが多い。
HAL をモックに差し替えれば、ホスト上でファジングできる。 ホストなら 1 秒に数千〜数万回実行できるので、実機の比ではない効率で見つかる。
CI に組み込むこと。 コミットのたびに数分走らせるだけでも効果がある。
5. SBOM — ソフトウェア部品表
CRA が明示的に要求する項目である。
SBOM とは、 「この製品には、どのソフトウェア部品が、どのバージョンで入っているか」の一覧である。
| 形式 | 特徴 |
|---|---|
| SPDX (ISO/IEC 5962) | Linux Foundation。ライセンス管理から発展 |
| CycloneDX | OWASP。セキュリティ用途に強い。脆弱性情報と組み合わせやすい |
| SWID タグ | ISO/IEC 19770-2 |
なぜ必要か
組み込みで実際に入っているもの:
| 部品 | 例 |
|---|---|
| RTOS | FreeRTOS、Zephyr、ThreadX、RT-Thread |
| TCP/IP スタック | lwIP、uIP、FreeRTOS+TCP、ベンダ独自 |
| TLS ライブラリ | Mbed TLS、wolfSSL |
| ファイルシステム | LittleFS、FatFs、SPIFFS |
| BLE / Wi-Fi スタック | ベンダ提供(中身が見えないことがある) |
| ブートローダ | MCUboot |
| ユーティリティ | zlib、cJSON、Protobuf-c |
| 標準ライブラリ | newlib、picolibc |
BLE / Wi-Fi スタックが最大の盲点である.
ベンダ提供のバイナリブロブになっていて、中身が分からないことがある。 だが過去に複数のチップベンダの BLE スタックで、 リモートコード実行を含む脆弱性が公表されている。
選定時に「ベンダの脆弱性開示ポリシーと、更新の提供期間」を確認すること。 これは 23 章の選定基準に含めるべき項目である。
SBOM の生成
| 方法 | 内容 |
|---|---|
| ビルドシステムから生成 | CMake / West / Yocto などが対応しつつある |
| バイナリ解析 | binwalk、cve-bin-tool などで既存バイナリから推定 |
| 手動 | 小規模なら現実的。だが維持が困難 |
Yocto / Buildroot ベースの Linux 組み込みでは、 ビルド時に SPDX を出力する機能が整備されている。
6. 脆弱性の追跡
SBOM を作っただけでは意味がない。継続的に照合する必要がある。
| 情報源 | 内容 |
|---|---|
| NVD (NIST National Vulnerability Database) | CVE の中央データベース |
| OSV (Open Source Vulnerabilities) | Google 主導。機械可読で使いやすい |
| GitHub Security Advisories | OSS の脆弱性 |
| ベンダのセキュリティアドバイザリ | チップベンダのものを必ず購読する |
| ICS-CERT / JPCERT | 産業制御系 |
| ツール | 内容 |
|---|---|
| cve-bin-tool | バイナリから使用部品を推定して CVE と照合 |
| Dependency-Track | SBOM を登録して継続的に監視する(OWASP) |
| Trivy / Grype | コンテナ・ファイルシステムのスキャン |
「影響評価」の工程が実務では最も重い.
CVE が出ても、自社製品では該当機能を使っていないことが多い。 全部に対応していたら、リソースが持たない。
VEX(Vulnerability Exploitability eXchange)という仕組みがある。 「この CVE は、当製品では影響しない(該当コードを呼んでいない、等)」 を機械可読な形で表明するものである。
CycloneDX や CSAF が VEX に対応している。 CRA 対応では、この「影響しない理由の記録」が重要になる。
7. 脆弱性開示ポリシー
PSTI・CRA・EN 303 645 すべてが要求する。
| 要素 | 内容 |
|---|---|
| 窓口 | security@example.com、または Web フォーム。見つけやすい場所に |
security.txt | RFC 9116。/.well-known/security.txt に連絡先を置く |
| 応答時間の約束 | 「3 営業日以内に受領確認」など |
| 開示の方針 | 「修正後 90 日で公開」など |
| 報告者への対応 | 法的措置を取らないことの明示(セーフハーバー) |
| 謝辞 | 報告者のクレジット。バグバウンティ(任意) |
「報告しても無視される」「訴えられる」と思われたら、 研究者は報告せずに公開するか、闇市場に流す.
報告しやすい窓口を作ることは、それ自体がセキュリティ対策である。
ISO/IEC 29147(脆弱性開示)と ISO/IEC 30111(脆弱性処理プロセス)が 参考になる。CRA の要求もこれらと整合している。
8. セキュア開発ライフサイクル(SDL)
| 段階 | やること | 章 |
|---|---|---|
| 要件 | セキュリティ目標、脅威モデリング | 02 |
| 設計 | アーキテクチャレビュー、信頼境界の確認 | 02, 07 |
| 実装 | 安全なコーディング規約、コードレビュー | 本章 |
| 検証 | 静的解析、ファジング、ペネトレーションテスト | 本章 |
| リリース | 最終レビュー、SBOM 作成、鍵の管理 | 本章, 12 |
| 運用 | 脆弱性監視、更新の配信 | 本章, 13 |
| 廃止 | EOL の通知、最終更新 | 14 |
標準:
| 標準 | 内容 |
|---|---|
| IEC 62443-4-1 | 産業用製品のセキュア開発ライフサイクル |
| ISO/SAE 21434 | 自動車のサイバーセキュリティエンジニアリング |
| NIST SSDF (SP 800-218) | セキュアソフトウェア開発フレームワーク |
| BSIMM / OWASP SAMM | 成熟度モデル |
CRA 対応の実質は、SDL の導入である.
CRA が要求するのは、個々の技術的機能というより、 「そういうプロセスが回っていること」とその文書化である。
IEC 62443-4-1 の認証を取っておくと、CRA 対応の大部分が済むという関係にある (03 章)。
9. この章のまとめ
| ポイント | 内容 |
|---|---|
| なぜ必要か | セキュアブートは脆弱なファームウェアを止めない。CRA の法的要件でもある |
| 組み込みの不利 | MMU なし・ASLR なし・W^X が甘い・クラッシュが見えにくい |
| 最も危険な箇所 | 認証前に処理されるコード(TCP/IP、BLE、TLS ハンドシェイク、USB) |
| 無料でできること | 警告を全部有効化、スタックカナリア、_FORTIFY_SOURCE、未使用コード除去 |
| ハードウェア支援 | Armv8.1-M の PACBTI(ROP 対策)、Cortex-A の PAC/BTI/MTE |
| 言語 | Rust を危険な部分だけに導入する段階的移行が現実的 |
| テスト | ファジングをホスト上で回す。CI に組み込む |
| SBOM | CRA の要求。BLE/Wi-Fi スタックが最大の盲点 |
| 脆弱性追跡 | SBOM × 脆弱性 DB を毎日照合。VEX で「影響しない」を記録 |
| 開示ポリシー | security.txt、応答の約束、セーフハーバー。報告しやすさ自体が対策 |
| CRA の実質 | SDL の導入と文書化。IEC 62443-4-1 が近道 |
次章では、第 V 部の残り——通信のセキュリティを扱う。