このサイトでの挿絵は、Gemini Proによる生成が大半です。 また、情報収集・まとめなどのサイトについては、検索結果をベースとしたものを使用しています。可能な限り出典を明示するよう努めますが完全ではありません。各自で調べる事もお忘れなく。

ビルドという無害な一手が牙をむいた日 — 北朝鮮のcrates.io汚染とTorvaldsが18回起動して見つけた1文字(2026/8/24 Linux・OSSトレンド)

はじめに

cargo build を打つ。apt upgrade を実行する。デバッグのためにマシンを起動し直す。どれも普段は何も考えずにやっている、無害に見える一手です。ところが今週は、その一手がいちばん深いところを開けてしまう出来事が重なりました。ビルドスクリプトが1行増えただけでインフォスティーラーが起動した事件、GPU ドライバのたった1文字のミスに気づくまでに18回もマシンを再起動した顛末、そして「待つだけ」のはずの割込み処理が高優先タスクを何ミリ秒も足止めしていた事実。無害に見える一手が、どこにつながっていたのか——そんな5本をお届けします。

1. 深夜の crates.io、86分間だけ開いた侵入口 — 北朝鮮 Sapphire Sleet のビルド汚染工作

2026年8月20日早朝(UTC)、Rust のパッケージリポジトリ crates.io に登録されている人気クレート arrayrefinternmentappend-only-vec の新バージョンが改ざんされました。攻撃の起点は、正規開発者 dtolnay の名前をたった1文字変えた偽アカウント dtolney です。攻撃者はこの偽アカウントを 01:17 UTC に作成し、8分後の 01:25 UTC には crates.io のアカウントも開設しています。ここまでは、よくあるアカウント準備の域を出ません。

不穏なのはその後の展開です。01:55 UTC、攻撃者はまず無害なデコイとして proc-macro1@1.0.106 を公開しました。中身に危険なコードは入っておらず、「実績のあるクレート作者」という信頼を演出するための布石だったと見られています。そして5時間ほど間を置いた 07:11 UTC、いよいよ悪意のある proc-macro1@1.0.107 がリリースされます。さらにその4分後の 07:15 UTC から 07:37 UTC までのわずか22分間で、3本の正規クレートの新バージョンが立て続けに公開されました。それぞれの Cargo.toml に追加されたのは、たった1行です。

1
proc-macro1 = "^1.0.107"

ライブラリ本体のコードには手を触れず、依存関係の記述だけを1行足す。これがこの攻撃の巧妙さです。既存の実装を書き換えていないため、差分レビューで「何かが変わった」と気づくのは簡単ではありません。多くの開発者が信頼して依存を追加する Cargo.toml の1行が、そのままインフォスティーラー起動の引き金になるという設計です。

build.rs が静かに実行すること

Cargo はビルド時に build.rs(ビルドスクリプト)を自動的にコンパイル・実行します。ここが今回の攻撃のいちばんの急所です。proc-macro1@1.0.107build.rs は、まず C2 サーバーの URL を Base64 でいくつかのフラグメントに分割した状態で埋め込んでおき、実行時にそれらを結合して復元します。静的解析ツールがソースコードの文字列を素直にスキャンしても、URL がそのままの形では存在しないため検出をすり抜けやすくなる仕組みです。

URL が復元されると、次は TLS 証明書の検証を無効化した HTTPS 通信で C2(23.254.165.112:9089 ほか)へ接続し、第二段階のバイナリをダウンロードします。動作しているプラットフォームが Linux・Windows・macOS のいずれかを判定し、それぞれに応じた形で展開する念の入れようです。Linux 環境では /tmp/rust-setup にバイナリを書き込んで実行権限を付与し、デタッチドプロセスとして起動します。

デタッチドということは、cargo build のプロセスが終了してもこのプロセスは切り離されて生き残り続けるということです。ビルドが終わって一見何事もなかったかのように見える裏で、バイナリだけが常駐を続けます。

第二段階バイナリの正体と、消えたときの備え

ダウンロードされる第二段階バイナリは Rust 製のインフォスティーラー兼バックドアです。ホスト名・OS 情報・インストール済みアプリの一覧を集めるだけでなく、Chrome・Brave・Edge が保存しているパスワードデータベース(SQLite)を直接クエリで抽出し、暗号資産ウォレットの拡張機能データまで収集します。

永続化の手口は OS ごとに使い分けられていて、Windows ではレジストリの Run キー、macOS では /Library/LaunchAgentsRunAtLoad 付きの LaunchAgent を設置、Linux では systemd のユーザーサービスとして登録します。仮に C2 サーバーが応答しなくなっても攻撃は止まりません。5日ごとに新しい .com ドメインを生成する DGA(ドメイン生成アルゴリズム)にフォールバックする作りになっており、テイクダウンだけでは根絶しにくい設計です。

なぜ北朝鮮なのか、そしてなぜこんなに速く消えたのか

Wiz の脅威インテリジェンスブログは、C2 インフラの重複を根拠に北朝鮮の国家的ハッカー集団 Sapphire Sleet への帰属を公表しました。使用された IP レンジや、過去に確認されている侵害インフラとの重なりが判断材料になっています。

同一の C2 IP は、Google Cloud Threat Intelligence による脅威クラスタ「UNC1069」の分析——npm axios の開発者を標的にした攻撃の調査——にも登場すると報じられています。この UNC1069 を北朝鮮に帰属付けているのは Mandiant です。Sapphire Sleet は同じくこの axios 攻撃などでも今回と同様のインフラを使ってきたグループで、今回はその標的を npm から Rust(crates.io)へ広げた形になります。

そして、この事件を象徴する数字が「86分」です。RustSec の公式アドバイザリ RUSTSEC-2026-0260によれば、arrayref の悪意バージョンが公開されてからパッケージが削除されるまでの露出窓は86分でした。人間の感覚では「あっという間」ですが、その短時間の中で 2,285 ダウンロードが記録されています。世界のどこかで、早朝(UTC)であっても CI/CD パイプラインが休みなく動き続けている証拠です。攻撃対象になったバージョンは下表のとおりで、影響を受けた可能性があるのはこの期間にビルドを実行した開発者・CI 環境です。

クレート悪意バージョン安全なバージョン
arrayref0.3.100.3.9 以下
internment0.8.70.8.6 以下
append-only-vec0.1.90.1.8 以下

RustSec のアドバイザリ自体は実際の悪用有無について言及していませんが、StepSecurity の分析では、GitHub Actions 上で攻撃を再現し、デモ環境でこのペイロードが実際に実行されて外部への接続が確立することまで確認されています。さらに、Linux 上で実際に感染した開発者からの被害報告もあったとされています。攻撃が実際に成立することを示す材料はすでに複数あり、油断はできません。

感染確認には grep -E 'arrayref.*0.3.10' Cargo.lock のようにバージョンを限定したパターンで Cargo.lock をチェックし、該当期間にビルドを行っていた場合は感染前提で対応するのが安全です。心当たりがあれば SSH 鍵・crates.io / API トークン・署名鍵・CI シークレットのローテーションを検討してください。

build.rs という構造的な弱点

今回の一件が改めて浮き彫りにしたのは、build.rs という仕組みそのものが抱える構造的な弱さです。build.rs はビルド時に任意のコードを実行できてしまうため、Rust が誇るメモリ安全保証の外側に存在します。コンパイラがどれだけ安全な言語仕様を守っていても、ビルドプロセスの一部として動く任意コードまでは守ってくれません。今回のような事件を受けて、build.rs のサンドボックス化をめぐる議論がエコシステム側で再び熱を帯びています。

2. 18回起動してたどり着いた1文字 — Torvalds と AI が追った Intel Xe GPU の謎

Linux カーネルの創始者 Linus Torvalds が、自身のマシンに載せた Intel Battlemage G21 GPU で起きた「起動のたびに画面が映らない」不具合と格闘した顛末が話題を呼びました。最終的に書かれた修正パッチはごくわずかな変更でしたが、そこにたどり着くまでに費やされたのは24本のデバッグパッチと18回のカーネル起動です。torvalds/linux の該当コミットには、その過程が刻まれています。

バグの舞台裏

問題の舞台は drivers/gpu/drm/xe/xe_vram.cget_flat_ccs_offset() 関数です。この関数は Intel GPU が内部で使う CCS(フラット CCS ストレージ)のベースアドレスをハードウェアレジスタから読み出し、そこから下の領域を「通常のビデオメモリ」としてアロケータに渡す設計になっています。

原因は、Mesa の VM のレベル3ページテーブルが、コールドブートのたびに毎回その末尾の小さな領域に配置されてしまうことでした。この配置により、コンポジターのバッチバッファヒープを覆うはずのエントリが失われてしまいます。その結果、コンポジターが最初にサブミットを行うタイミングでフォールトが発生し、GDM(GNOME Display Manager)が再起動を繰り返すという症状になっていたのです。

なお、この現象が確認されたのは GDM 環境で、他のディスプレイマネージャやコンポジター全般にまで一般化できるかどうかは分かっていません。フレームバッファや仮想コンソール自体は正常に動作していたため、一見するとブート処理そのものの不具合に見え、原因の特定を難しくしていました。

24本のパッチ、18回のブート、そして1文字

原因を突き止めるまでの道のりは、ひたすら手を動かす作業の連続でした。Torvalds は毎回、カーネルのどこに drm_info()WARN によるログ出力を仕込むかを考え、デバッグ用のパッチを書いてはコンパイルし、実機で起動してログを確認する、という作業を繰り返しました。この試行錯誤は24本のデバッグパッチと18回の起動という回数に表れています。そして18回目の起動で、ようやく犯人が特定されました。

最終的な修正は驚くほど小さなものでした。オフセットの計算方法を「切り上げ(round_up)」から「切り捨て(round_down)」に変え、アライメント単位も 128KiB から 4KiB へ縮める、実質1文字を書き換えるのに等しい変更です。

1
2
3
4
5
/* 修正前 */
offset = round_up(offset, SZ_128K);

/* 修正後 */
offset = round_down(offset, SZ_4K);

「切り上げ」を「切り捨て」に変えるだけで、アロケータに渡す VRAM の上限が CCS 領域の手前に収まるようになります。修正後のコードには、CCS ストレージが GSM(Global Stolen Memory)と重複しないことを直接検証する WARN アサーションも追加されており、同種のバグを将来早期に検出できるようになりました。24本のパッチと18回のブートという長い調査の果てに、結論は1行の書き換えだったという落差こそが、このエピソードの印象を強くしています。

AI という相棒との距離感

この調査の過程には、AI がデバッグの相棒として登場します。Torvalds は毎回どこにログ出力を仕込むかを AI と相談しながら、コンパイル・起動・ログ確認を繰り返しました。Torvalds 自身の言葉を借りれば「地獄のようなデバッグセッションだったが、AI が泥臭い作業の多くを大いに助けてくれた」というものです。

ただし、ここで見過ごせない事実があります。調査の途中、AI は 何度も 「これは解決不可能だ、報告書を書くべきだ」と作業の打ち切りを進言していました。それでも Torvalds は調査を続けさせ、最終的に18回目の起動で犯人を突き止めています。AI の助言をそのまま受け入れて調査を打ち切っていたら、このバグはもっと長く放置されていたかもしれません。

なお、動画のタイトルなどでは特定のモデル名が取り沙汰されていますが、当のコミットメッセージには単に「an AI」とだけ記されており、どのモデルだったかの明記は確認できていません。

影響を受ける環境と対処

直接影響を受けるのは Intel Battlemage(Arc B580/B770 など B 系)GPU を Linux デスクトップで使っているユーザーです。Linux 7.3 以降には修正が取り込まれており、安定版(7.2 系以前)へのバックポートを待つか、変更箇所が1行のみなので drivers/gpu/drm/xe/xe_vram.c に手動で cherry-pick することもできます。暫定回避としては、ディスプレイマネージャを GDM から SDDM や LightDM に切り替える方法と、カーネルパラメータ xe.force_probe='!<device_id>' で drm/xe ドライバを無効化して旧 i915 ドライバにフォールバックする方法があります。

3. 定番タイトルたちの Linux 版だけが壊れる理由 — Proton 11.0-2 が埋めた穴

Valve が 2026年8月21日、Proton 11.0-2 の公式リリースを公開しました。Wine 11.0 系への移行(Proton 11.0-1)で生じた約20件のリグレッションを解消し、9タイトルを新たに「Now playable」へ追加。Helldivers 2・Marvel Rivals・Forza Horizon 4/5/6 など、ゲーム側のアップデートに起因する不具合も合わせて修正されています。

構成コンポーネントを見るときは、どのコンポーネントの話かを取り違えないことが大切です。今回搭載されたのは Wine Mono 11.2.0、FEX 2607、dxvk-nvapi v0.9.2、そして vkd3d-proton v3.0a-252(proton-11 ブランチ)。ここで紛らわしいのが、Valve が独自拡張しゲームの D3D12 描画に実際に使われる「vkd3d-proton」と、Wine プロジェクト本体が管理するベースライン実装「vkd3d」(今回 2.0 がリリース)は別物という点です。名前は似ていますが開発ラインが異なります。

Helldivers 2 はゲームアップデート後に起動不能だった問題が、Marvel Rivals は同様のクラッシュが、Forza Horizon 4/5/6 は最近の SteamOS でのブラックスクリーンがそれぞれ修正されました。ほかにも Path of Exile のチャットテキストによるクラッシュや、HITMAN World of Assassination のメモリリークなど、細かな修正が積み重なっています。Windows 向けに出たゲームパッチが Linux 環境を壊し、Valve がそれを追いかけて直す、という構図が今回も繰り返された形です。

4. 「ゾーン」から「namespace」への継承ミス — OpenZFS が塞いだコンテナ越境の抜け道

2026年8月21日、OpenZFS 2.4.4 など3系統の公式リリースが同時に出ました。目玉は、非特権コンテナが Linux の namespace 内で持つ CAP_SYS_ADMIN を、ZFS 側がホスト全権と誤認してしまう設計上の穴の修正です。Mallory Security の Erica Windisch 氏によるレポートを発端に8件の脆弱性(OZ-1〜OZ-8)が確認され、うち2件がこのリリースで修正されました。

2つのバグが連鎖する構造

OZ-1 と OZ-2 は単独でも問題ですが、組み合わさることで一つの攻撃チェーンを形成します。PR #18959 で対応された OZ-1は、secpolicy_sys_config()secpolicy_zinject() が、呼び出し元の資格情報がグローバルゾーン(ホスト)由来かどうかを検証していなかった問題です。Linux の user namespace 内で CAP_SYS_ADMIN を持つプロセスは、本来 namespace 内に限定された権限しか持たないはずですが、OpenZFS はこれをホスト全権と誤認し、プールの破壊・履歴の読み取り・zinject(I/O エラー注入)といったホスト操作をそのまま許可していました。

PR #18960 で対応された OZ-2は、vdev_open() がブロックデバイスを開く際、呼び出し元の資格情報で DAC パーミッションを確認していなかった問題です。CAP_SYS_ADMIN は持つが CAP_DAC_OVERRIDE は持たないコンテナプロセスが、本来アクセスできないはずのデバイスを zvol のミラーレグとして追加し、持続的な書き込みを行える状態になっていました。この2つが連鎖すると、namespace 内の権限だけでホストのストレージ層に手を伸ばせてしまう、という構図が成立します。

根本原因は Solaris 設計との乖離

なぜこのような取り違えが起きたのか。もともと OpenZFS が Solaris の Zones(全権限分離モデル)を前提に設計されていたことに行き着きます。Solaris のゾーンモデルでは権限は明確に分離されている一方、Linux の user namespace では namespace 内でも CAP_SYS_ADMIN が付与されうるという、前提の異なるモデルです。この設計思想の違いを OpenZFS が十分に考慮しないまま実装を継承してきたことが、問題が長年にわたって放置されてきた根本原因だと説明されています。

あわせて、フェールオーバー時にプールが宙吊りになる問題を手動で解消する zhack mmp reclaim コマンドも追加されました(PR #18892)。MMP(Multi-host protection)はプールの二重マウントを防ぐ仕組みですが、接続されていたミラーレグが消えるとクレームが永遠に拒否されてプールが宙に浮いてしまうことがありました。このコマンドは到達不能なレグへの書き込み要件を緩和して強制インポートするもので、「ピアが確実にダウンしている」という人間の判断を前提にした手動復旧ツールという位置づけです。

まだ残っている6件

対象になるのは、/dev/zfs にアクセスできる非特権コンテナを起動できる環境です。コンテナを使わない従来型の NAS やストレージ専用サーバーでは影響は小さいとされています。即時の推奨対応はバージョンアップ(2.4.x → 2.4.4 など)で、暫定策として非特権 user namespace を無効化する、あるいは /dev/zfs の権限を絞る方法もありますが、いずれもコンテナ運用へのトレードオフを伴います。

ここで見落とせないのは、OZ-1・OZ-2 が直っても話が終わっていない点です。OZ-3〜OZ-8 を含む残り6件は、今回のリリース時点でまだ未修正のまま残っています。今回のリリースは全体像の一部を塞いだに過ぎず、継続的な注意が必要な状態です。

5. 割込みを待つだけで何が起きていたか — Linux 7.3 が縮めた16ミリ秒の待ち時間

2026年8月22日、Linux 7.3 の x86/mm ツリーに、TLB(Translation Lookaside Buffer)フラッシュ処理を見直すパッチシリーズがマージされました。投稿者は Bytedance のエンジニア Chuyi Zhou 氏です。

問題の核心:待っているだけなのにスケジュールされない

x86-64 では、仮想アドレスから物理アドレスへの変換キャッシュである TLB を無効化するために IPI(プロセッサ間割込み)を使います。あるプロセスが終了したりページが回収されたりするたびに、カーネルは複数の CPU へ TLB シュートダウンを要求し、それぞれの処理完了を待ちます。

ここに落とし穴がありました。smp_call_function*() 系関数は、IPI を送信してから処理完了を待機するまでの操作全体を通じて、呼び出し元 CPU のプリエンプションを無効化したままにしていたのです。つまり、ただ「待っているだけ」の間、その CPU 上では高優先タスクがまったくスケジュールされない区間が生まれていました。CPU 数が増えるほど IPI の往復にかかる時間も伸びるため、この待機区間はコア数の多い環境ほど深刻になります。Bytedance の16コア本番環境での計測では、この待機に起因するスケジューリング遅延が最大 16ms 程度に達していたと報告されています。

解決策:per-task CPU マスクによるタスクローカル化

解決の中核は、待機対象の CPU 集合を per-task(タスクごと)の CPU マスクとして持たせる設計変更です。まず flush_tlb_info 構造体を per-CPU 変数からスタック上のローカル変数へ移すことで、途中でプリエンプションが起きても特定の CPU に縛られなくなります。次に smp_call_function_any() では、CPU を固定してプリエンプションを無効化する get_cpu()/put_cpu() の呼び出しを guard(migrate)() に置き換え、スケジューリングは可能なまま CPU マイグレーションだけを禁止する形にしました。さらに flush_tlb_kernel_range() ではプリエンプションの無効化自体をやめ、INVLPGB 機能が必要な内部処理にのみ無効化区間を限定しています。

LKML に投稿されたカバーレターにあるとおり、これは「IPI の完了を待つ間もプリエンプションを許す」という趣旨の変更で、IPI 送信後・待機開始前にプリエンプションを再度有効化できるようになりました。この設計により、どの CPU の応答を待っているかがタスク固有のマスクで追跡され、待機中に高優先タスクが割り込んで実行できるようになります。

この変更を経て、Bytedance の計測値は最大 16ms 程度あった遅延が約 1.5ms まで縮小したと報告されています。パッチは Intel の Dave Hansen 氏が x86/mm ツリーに取り込み、10ラウンドにわたる LKML でのレビューを経て採用されました。Hansen 氏自身は「確認すべき回帰はあるが、注意して見ていくべきものだ」という慎重なコメントを残しており、手放しの称賛というよりは、様子を見ながら受け入れるという姿勢がうかがえます。

誰に効くのか

恩恵を受けるのは、スケジューリング遅延のスパイクが致命的になる用途です。DPDK のようなマイクロ秒単位のレイテンシが要件になるパケット処理ワークロードでは、16ms という遅延は許容できる範囲を超えています。産業用制御やオーディオ処理などのリアルタイム Linux 環境、MMORPG や FPS 系のゲームサーバー、そして揺れが直接損益に影響する高頻度取引システムも、同様にこの改善の恩恵を受ける対象です。効果はコア数が多い環境ほど顕著とされ、4〜8コア以下の環境では改善が限定的になる可能性があります。

Phoronix の解説にもあるとおり、Linux 7.3 は 2026年秋ごろのリリースが見込まれています。7.3 を待たずに恩恵を受けたい場合は、linux-next ツリーや 7.3-rc ビルドを試す、あるいはステージング環境で十分にテストした上でバックポートを検討する形になります。既存の暫定策としては、isolcpustaskset で DPDK のワーカースレッドを専用 CPU へ隔離し、TLB フラッシュ IPI の影響を受けにくくする運用も有効です。

まとめ

今週の5本を並べてみると、共通しているのは「普段は意識しない一手」が持つ重みです。cargo build を叩くという行為が北朝鮮のインフォスティーラー起動につながり、再起動を繰り返すという手作業の積み重ねが GPU ドライバのバグを暴き、IPI 完了を待つだけの区間がミリ秒単位の遅延を生んでいました。Proton 11.0-2 や OpenZFS 2.4.4 のような修正の積み重ねも、結局は同じビルド・パッケージング・権限モデルという土台の上で成り立っています。派手な脆弱性のニュースだけでなく、こうした「無害に見える一手」がどこにつながっているかを意識することが、日々 OSS と付き合う上でのちょっとした防御線になるのではないでしょうか。

参考リンク

Hugo で構築されています。
テーマ StackJimmy によって設計されています。