ビルドツールチェーン監査

autotools ビルドチェーン、GitHub Actions CI、 ベンダーされたソースの来歴、インストール経路のリスクを レビュー。何が固定済みで、何が署名済みで、何が未対応か 正直に書きます。

ツールチェーンリスク · CI リスク · ソース来歴 · 配布リスク · まとめ

1. ビルドツールチェーンリスク

lha ソースは GNU autotools を使用。リリースバイナリは alpine:3.20 Docker コンテナ内でビルドされ (ホストは GitHub Actions Linux runner)、その後 macOS / Windows runner でパッケージ。ツールチェーン: autoconf 2.72automake 1.16.5libtool 2.5.4gcc 13.2.1musl 1.2.5(監査時点の alpine:3.20)。

bash scripts/build.sh
  ( cd "$SRC" && autoreconf -is )          # m4 マクロ展開
  ( cd "$BUILD_DIR" && "$SRC/configure" )  # 生成された shell スクリプト
  ( cd "$BUILD_DIR" && make -j"$JOBS" )    # cc + ld

この 3 ステップはそれぞれビルドホスト上で任意のコードを 実行します。以下、リスク別の監査。

R1. autoreconf -is — M4 マクロ展開

何をするかconfigure.ac を autoconf + automake + libtool + autoheader + autopoint で 展開して configure を生成する。M4 はマクロ 言語で、shell を呼んだり、プログラムを走らせたり、 ファイルを読み込める。

リスクupstream/lha/configure.ac.m4 ファイルに バックドアがあれば、ビルド時に任意のコマンドが走る。 ベンダーされたソースはバイト単位で upstream jca02266/lha@86094cb と一致するため、これは upstream 信頼の問題で、ljh-sh 特有ではない。 緩和は §3 を参照。

現在の緩和:lha 1.14i の M4 入力ファイルは小さく、 2003 年から実質的に変わっていない。configure.ac 全体を読み、不審な AC_RUN_IFELSE / AC_TRY_RUN / AC_LINK_IFELSE 本体は ない(5 軸ソース監査 の一部)。

R2. 生成された configure スクリプト

何をするか:~10,000 行の shell でツールチェーンを 検出し、AC_TRY_RUN 試験(実 fork + exec + wait で小さな試験 プログラム)を動かし、Makefile を出力する。

リスク:侵害された autoconf は任意のコマンドを 走らせる configure を生成する可能性がある。 生成された configure(~10,000 行)は直接 監査しない。元になる configure.ac (~300 行)にあるバックドアは見えるが、autoconf の M4 マクロにあるバックドアは再生成まで隠れる。

現在の緩和alpine:3.20(イメージ)に 固定している。リスク:イメージは フローティングタグで digest ではない。Alpine 3.20 が強制リビルドされる(セキュリティ事故)と CI が静かに 取り込む。1 行修正:workflow で docker: image: alpine@sha256:<digest>、 digest は既知良好な docker pull alpine:3.20 から取得。

R3. make + cc

何をするかgcc -g -O2 -DHAVE_CONFIG_H ... で C ソースをコンパイルし、リンクする。

リスク:C ビルドの標準。-g -O2 は安全; ビルド時の懸念は Makefile が shell を呼ぶ箇所のみ。 生成された Makefile を shell injection パターン (変数のクォート漏れ、glob のクォート漏れ等)で確認、 該当なし。

現在の緩和:C は標準 autoconf 検出フラグでコンパイル。 LTO なし、PGO なし、サードパーティコンパイララッパなし。 ビルドは bit-for-bit 再現可能(別ホストで再実行、ビルド タイムスタンプが __TIME__ に焼かれる点を除き 一致——lha の __TIME__ はバージョン文字列の 出力にのみ使用、ランタイム挙動に影響なし)。

R4. libiconv / libz / libSystem 依存

static-musl ビルドは C ライブラリのみリンク。macOS ビルドは システム libiconv を使用(macOS では libSystem に含まれる)。Linux gnu ビルドは apt パッケージの libz + libiconv を リンク。なしlibcurllibssllibxml2libsystemd

リスク:低 — すべてパッケージマネージャ由来;唯一の ソフトウェア定義入力は workflow で固定されたパッケージ名。

2. CI リスク

lha リリースパイプライン:

on:
  push:
    tags: ['v*']
  workflow_dispatch:
jobs:
  build:
    steps:
      - uses: actions/checkout@v4         # ❌ 未固定
      - uses: msys2/setup-msys2@v2       # ❌ 未固定
      - run: bash scripts/build.sh        # ✅ リポジトリ内
      - run: docker run alpine:3.20 ...  # ❌ 未固定
      - uses: softprops/action-gh-release@v2  # ❌ 未固定

R5. 未固定のサードパーティ actions

リスク:高。actions/checkout@v4msys2/setup-msys2@v2softprops/action-gh-release@v2 — すべて フローティングタグ。書き込み権限のある者(アカウント 乗っ取り含む)は CI 環境で任意のコードを送り込み、 secrets.GITHUB_TOKEN と release 書き込み権限を 得られる。

1 行修正:各 uses: を commit SHA に 固定。GitHub の セキュリティ ハードニングガイド も推奨。

現在の緩和:なし。リスクは上流リポジトリの書き込み 権限者数(小)と、怪しいリリースに気付く確率(低 — artifacts 変化に気付く必要あり)で抑止されているのみ。

R6. 未固定の alpine:3.20

リスク:中。上記と同じフローティングタグ。digest に 固定する。

R7. CI runner の secrets / 書き込み権限

リスクljh-sh/lha への push 権限を持つ 者なら誰でも workflow を改変できる(メンテナの GitHub 身元で実行、secrets.GITHUB_TOKEN + release 書き込み権限付き)。

現在の緩和:ブランチ保護ルール(PR review 必須)— 確認 済み。Release は v* tag push 時のみ — メンテナ による署名タグ push が必要。PR 作成者は単独で release を トリガできない。

1 行改善:CODEOWNERS ファイルを追加し、workflow 改変は特定メンテナの review を必須にする。

3. ベンダーされたソースの来歴

upstream/lha/ はバイト単位で jca02266/lha@86094cb (LHa for UNIX 1.14i-ac20220213)と一致。Vendoring は git subtree addhttps://github.com/jca02266/lha.git master 86094cb から実施;subtree 履歴は upstream/lha/.git と squash-merge コミット内に保存。

R9. Subtree vendoring は再現可能

ベンダーされたコミット(履歴の merge commit 4ccece7...)は正確な upstream コミットを参照。 いつでも検証可能:

git -C upstream/lha log -1 --format='%H %s'
git ls-remote https://github.com/jca02266/lha.git 86094cb

SHA が一致すれば、ベンダーされたソースは upstream の bit-for-bit。CI に毎回 release 時にこれを実行するステップを 追加すべき(release job に 1 行)。

R10. ベンダー信頼点は upstream

jca02266/lha の履歴が後に改変されても (force-push、rebase、削除)、ベンダーされたコピーは 変わらない— スナップショットがある。ただし 我々のリポジトリが release 前に侵害されると、 攻撃者は upstream スナップショットと同じに見える バックドア版でベンダーソースを差し替え可能。

1 行修正:CI で checkout 後に upstream/lha/.git が期待 86094cb SHA に一致するか検証。不一致ならビルド失敗。これが 「我々の lha は本当に upstream 由来」チェック。

4. 配布 / インストール経路リスク

ユーザは以下のいずれかでバイナリを取得:

R11. Release 未署名

リスク:中。Release artifacts(tarball、zip)は何も 署名していない。GitHub の commit 署名は commit を保護するが release artifact は保護しない。GPG 署名なし、cosign 署名 なし、sigstore envelope なし。

1 行修正:release workflow に cosign sign-blob ステップ追加。GitHub が OIDC ベース keyless 署名を提供(cosign sign-blob)。

R12. x eget use lha は GitHub 提供の SHA256SUMS を検証するが、checksum ファイル自体は未署名

前版の本ページへの訂正。eget はデフォ ルトで checksum を検証します — GitHub の release から SHA256SUMS(または各 asset の .sha256)ファイルを取得し、ダウンロードし た asset の hash と比較します。一般ユーザは x eget use lha を実行するたびに checksum 検証を得ます。本ページの以前の説明(eget は TLS のみで 検証)は誤りでした。

残る課題。SHA256SUMS ファイルもバイナ リ asset も同じ GitHub release に紐づきます。GitHub アカ ウントの侵害 — あるいはメンテナによる release 編集権限の 悪用 — は両方を一度に差し替え可能。Checksum ファイル自 体は署名されていないので、eget の検証は asset と checksum の間の内部一貫性をチェックするもので、 それぞれの出所ではありません。

1 行修正:R11 と同じ — 各 release asset に cosign sign-blob(keyless、GitHub OIDC 経 由)。これで GitHub の checksum の上に sigstore 署名が一 層乗ります。強い完全性を求めるユーザはダウンロード後に cosign verify-blob を実行。アカウント侵害後 のギャップを塞ぎます。

R13. SBOM なし

リスク:小さい静的バイナリには低。静的バイナリの唯一の 「コンポーネント」は libc(macOS では libSystem、OS の一部)。 lha 自体のみ。SBOM 価値は限定的。

5. まとめ — 実際にやる変更

impact-to-effort 比率順(高い順):

#変更 工数低減するリスク
R9 CI で subtree SHA 検証 5 分 「我々の lha は upstream 由来ではない」攻撃面を捕捉
R5 uses: を commit SHA に固定 15 分 action タグ移動攻撃面を排除
R6 alpine:3.20 を digest に固定 5 分 イメージ再ビルド攻撃面を排除
R11 cosign で各 release artifact 署名 30 分 配布チャネルの完全性底
R7 CODEOWNERS for .github/ 10 分 CI 挙動を改変できる人を限定
R13 SBOM を release asset に 30 分 コンプライアンス

合計 ~1.5 時間の作業で業界標準 → 十分ハードニングへ。