世界を動かす技術を、日本語で。

カーネルのバグは平均で2年間隠れ続ける。中には20年隠れるものもある

2026年1月8日原文(pebblebed.com)

概要

  • Linuxカーネルのバグは 平均2.1年 発見されずに残存
  • CAN busSCTP など一部サブシステムでバグ寿命が特に長い
  • バグ検出は年々 高速化 しているが、古いバグのバックログが存在
  • 自己修正 (バグ導入者自身が修正)も多く、コード所有意識が影響
  • 長寿命バグは 参照カウントミスレースコンディション などが多い

Linuxカーネルのバグ寿命と発見の傾向

  • Fixes:タグ 付きのバグ修正ペアを 125,183件 分析
  • 有効な記録 は123,696件(寿命0~27年)
  • 平均バグ寿命 は2.1年、最長は 20.7年 (ethtoolのバッファオーバーフロー)
  • 2010年では 1年以内発見率0%、2022年には 69% に向上
  • VulnBERT によるバグ検出精度は 92.2%、偽陽性率は1.2%(CodeBERTは48%)

バグ発見までの時間とその変化

  • 2025年のみのデータでは 平均寿命2.8年、全履歴では 2.1年 に短縮
  • 5年以上発見されないバグ は全体の13.5%(全履歴)、19.4%(2025年のみ)
  • バグ発見までの速度は 年々向上 傾向
    • 2010年導入バグ:平均寿命9.9年、1年以内発見0%
    • 2022年導入バグ:平均寿命0.8年、1年以内発見69%
  • SyzkallerKASAN などのサニタイザ、静的解析、レビュー体制強化が寄与

バグの発見と修正のパターン

  • 新規バグは 早期発見、古いバグは バックログ として残存
    • 2024-2025年修正バグの60%が直近2年で導入
    • 18%が5-10年前、6.5%が10年以上前に導入
  • カーネルの Fixes:タグ を活用したバグ追跡手法
    • git logによるFixes:タグ抽出
    • 修正・導入コミットの日付取得
    • サブシステム分類・バグ種別分類
    • バグ寿命計算

サブシステムごとのバグ寿命

  • CAN bus (4.2年)、 SCTP (4.0年)、 USB (3.5年)などが長寿命
  • BPF (1.1年)、 GPU (1.4年)は短寿命
  • ニッチなプロトコルテストカバレッジ不足 が長寿命の要因
  • GPUBPF は専用のファジングインフラ整備により短期間で発見

バグ種別ごとの寿命

  • レースコンディション は平均5.1年と最も発見が遅い
  • 整数オーバーフロー (3.9年)、 use-after-free (3.2年)、 メモリリーク (3.1年)なども長め
  • null参照デッドロック は比較的早期に発見

長寿命バグの特徴と事例

  • 参照カウント漏れNULLチェック漏れ整数オーバーフロー状態機械のレース が典型
  • 19年間修正されなかった netfilterのrefcountリーク 事例
    • テスト条件が特殊で再現困難
    • メモリリークとして長期間放置
  • 不完全な修正 も多く、"未定義動作"や"再現できなかった"旨のコミットは要注意

なぜ一部バグが長期間隠れるのか

  • ファジングカバレッジ不足
    • Syzkallerはシステムコールには強いが状態遷移が必要なプロトコルに弱い
  • トリガー条件が複雑
    • 特定のパケットシーケンスや同時実行、メモリ圧迫などが必要
  • 古いコードのレビュー不足
    • "安定"している部分は開発者の目が届きにくい

長寿命バグのアナトミー

  • 参照カウントミス
    • 例:kref_get後にエラーパスでkref_putし忘れ
  • NULLチェックタイミングの誤り
    • 取得直後にデリファレンスし、その後でNULLチェック
  • 整数オーバーフロー
    • ユーザー入力からのサイズ計算ミス
  • 状態機械のレース
    • ロック解除直後の状態変化タイミングの競合

今後の課題と展望

  • 検出ツールのさらなる精度向上
    • VulnBERTのようなAI活用による検出率向上
  • テストカバレッジの拡大
    • ニッチサブシステムや複雑な状態遷移への対応
  • コード所有意識とレビュー体制の強化
    • バグ導入者自身による修正の促進
  • 不完全修正の早期発見
    • "未定義動作"や"再現できなかった"コミットへの追加レビュー

Hackerたちの意見

Firefoxのバグって、そんなに長く放置されるんだね。

俺が好きなFirefoxのバグの一つは、詳細はあんまり覚えてないけど、こんな感じだったかな。「この設定ファイルを使ってるとクラッシュする。」もうちょっと複雑だったけど、結局は何らかのクラッシュ。20年後、やっとそのバグが閉じられたんだ。見て、彼らは設定パーサーをRustで書き直して、今はこれが修正されたんだって。クールだけど、俺が覚えてるのはそこじゃない。いつも考えるのは、バグがオープンされた直後に「ごめん、バグを直す前に自分たちのプログラミング言語を書かなきゃいけないんだ。心配しないで、戻ってくるから、ちょっと時間がかかるけど。」って返答することを想像してみて。誰も信じないよね。でも、実際に起こったことなんだ。

どんなソフトウェアにも長生きするバグがあるよ。存在する限りバグがないものはないから、ほぼ避けられない。Windowsのバグトラッカー見たことある?アンチFirefoxの連中は本当にそれを攻撃しようとしてる。この記事のポイントはLinuxを批判することじゃなくて、もっと生産的なコードレビューにつながる分析なんだ。

もしかしたら俺のシステムだけかもしれないけど、時間がハイパーリンクみたいに見えるのに、なぜかリンクになってないんだよね。特に、コミットハッシュがカーネルリポジトリの実際のコミットにリンクしてないのが残念。

CSSでホバーすると色が#79635cになるタグなんだよね。確かに変なスタイル選択だけど、意味的にはリンクじゃないんだよ。

「Rustで書き直せ」ってコメントがスレッドを占拠する前に言っとくけど、ここで説明されてるバグのクラス(高並行状態機械の論理エラーや不正確なハードウェアの仮定)は、必ずしも借用チェッカーで捕まるわけじゃないよ。Rustはメモリ安全性に関しては素晴らしいけど、ネットワークカードの仕様を誤解したり、DMAとやり取りする不安全なロジックでレースコンディションを書くのを防いではくれない。とはいえ、メモリ安全性の問題を占める70%のバグを排除できれば、こういう深い論理バグを見つけるためのSNR比は劇的に改善されるはず。セグフォルトを追跡するのに時間をかけすぎて、微妙な破損バグを見逃しちゃうんだよね。

ここで説明されてるバグのクラス(高並行状態機械の論理エラーや不正確なハードウェアの仮定)は、必ずしも借用チェッカーで捕まるわけじゃないよ。Rustはメモリ安全性に関しては素晴らしいけど、ネットワークカードの仕様を誤解したり、DMAとやり取りする不安全なロジックでレースコンディションを書くのを防いではくれない。Rustはメモリ安全性だけじゃなくて、代数データ型やRAIIなどもあって、こういう馬鹿げた論理バグを捕まえるのに大いに役立つよ。

ここで説明されてるバグのクラス(高並行状態機械の論理エラーや不正確なハードウェアの仮定)は、必ずしも借用チェッカーで捕まるわけじゃないよ。あなたが説明しているバグは確かにRustの借用チェッカーでは直接対処されないものだけど、記事はあなたのコメントが示唆するよりも広い範囲をカバーしていると思うよ。例えば、記事のかなりの部分(ほとんど?)は、収集したデータを分析することに費やされていて、バグをサブシステムごとにグループ化しているんだ。サブシステム バグ数 平均寿命 drivers/can 446 4.2年 networking/sctp 279 4.0年 networking/ipv4 1,661 3.6年 usb 2,505 3.5年 tty 1,033 3.5年 netfilter 1,181 2.9年 networking 6,079 2.9年 memory 2,459 1.8年 gpu 5,212 1.4年 bpf 959 1.1年 またはバグのタイプごとに: バグタイプ 数 平均寿命 中央値 race-condition 1,188 5.1年 2.6年 integer-overflow 298 3.9年 2.2年 use-after-free 2,963 3.2年 1.4年 memory-leak 2,846 3.1年 1.4年 buffer-overflow 399 3.1年 1.5年 refcount 2,209 2.8年 1.3年 null-deref 4,931 2.2年 0.7年 deadlock 1,683 2.2年 0.8年 さらに、10年以上続くバグの一般的なパターンを説明するセクションには、以下のように書かれている: > 1. 参照カウントエラー > 2. デリファレンス後のNULLチェックの欠如 > 3. サイズ計算における整数オーバーフロー > 4. 状態機械におけるレースコンディション これらはすべて、あなたのコメントに書かれているよりも広い範囲をカバーしているよ。さらに、19年前のバグのケーススタディは、高並行状態機械やハードウェアの仮定とは関係ない参照カウントエラーなんだ。

これは、批判者にも支持者にもあまり評価されていない部分だと思う。Rustを使うと、普通のメモリ安全性について深く考えずに「リスク」をもっと取れるんだ。コードの構造を整えて、ロジックが明らかに正しいようにすることを優先してる。C++では、メモリ安全性を超シンプルに保つことが最重要で、例えばstd::string_viewをどこかに保存することはほとんどないよ。Rustでは、好きなところに&strを置くだけ。間違えたらコンパイル時に分かるしね。

同時状態機械の例は、ロックのエラーみたいに見える?その間に変更されないという前提なら、ロックは保持し続けるべきじゃない?その場合、Rustのロックが役立つよ。データを埋め込むことができるから、保持されていないと触ることすらできないんだ。

Rustは多くのバグを防げるし、状態機械の保証もモデル化できる。全部をRustで書き直すのは非常にコストがかかるから、すぐには実現しないだろうね。

他のトップレベルのコメントではRustについて言及されていないし、TFAもRustやメモリ安全性のようなトピックには触れていない。ただのバグの話だよ。Rustのファントム熱心さは残念ながら本物だね。[1] ああ、でもRIRのコメントを投稿前に却下することの冷却効果があるよね…

Hacker Newsで議論の続きを見る