GentooのGitHubがクラックされてrm -r /入ってたそうだけどやばいの?

GentooGitHub リポジトリが乗っ取られて, 復旧作業のためアクセスできなくなってますね.

infra-status.gentoo.org

どうやら ebuild (パッケージビルド&インストールするためのbashスクリプトファイル)に "rm -rf /*"とかもしこまれていたとか.

なんか見た感じやばそうだけど, 実際のところやばいんでしょうか?

まあ, もちろんのっとられたからにはやばいし, しばらく該当 GitHub リポジトリを避けておくのがいいんですが, 実際どのぐらいなにが起きるぐらいやばいんでしょうか?

ということで, 以下の話をします.

  • やられたリポジトリがやばくない
    • ミラーだから, 開発者は使わないよ
    • いろいろないから, 一般ユーザも普通使わないよ
    • プルリク受けつけと、まあバックアップぐらいのとこだよ
  • 書かれたコマンドがやばくない
    • ebuild の先頭に rm -rf 書いても動かないよ
    • /bin/rm でも sandbox で止まるよ
  • その他
    • せっかくだし git から sync してる人は PGP の verify は有効にするとよさそう

やられたリポジトリがやばくない

f:id:meech:20180701213516p:plain:w2368:h300

Gentoo のパッケージリポジトリは, 3つの場所で公開されています. 1つは開発者が commit を行うリポジトリGentoo 公式の git.gentoo.org 上でホスティングされています.

2つ目は, GitHubgentoo/gentoo にある, このリポジトリのミラーです. 定期的に git.gentoo.org から commit が 上書き されてきます.

3つ目は, GitHubgentoo-mirror/gentooリポジトリです. 一般ユーザがパッケージツリーを git pull したい時に使います.

今回やられたのは, 2番目の GitHubgentoo/gentoo にあるリポジトリです. 開発者はここには push しませんし, そのうちミラーで上書きされる(らしい)ので開発者のコードがやられた状態ではありませんでした.

では, ユーザ側はどうでしょうか? このミラーから pull していることはないのでしょうか?

ここで少し Gentoo のパッケージツリーの話をします. Gentoo のパッケージ情報は"Portageツリー"と呼ばれ, 各パッケージのebuildファイルが, "カテゴリ/パッケージ名"のディレクトリの下に配置されています. Portageツリーの中には膨大な量の ebuild ファイル(いま見たら35,537個)が入っています. パッケージのインストール・更新時には, この Portage ツリーをひたすらなめていく………のはちょっと大変なので ebuild のキャッシュがあればそれを読みます. これによって, パッケージのインストールが高速化されているわけです.

このキャッシュの内容自体は ebuild の内容とかぶっている(キャッシュなので当然)ので, 1番目の開発者のリポジトリにも, そのミラーである2番目のリポジトリにも入っていません. キャッシュは, 3番目のリポジトリにだけ入っています. すなわち, git.gentoo.org にホストされている開発者リポジトリから, ebuildファイルをコピーして, キャッシュを生成・追加したものが3番目のリポジトリ(あと rsync や http でも取得できる)として公開されています.

つまり, ユーザは3番目のリポジトリからgit pull してきて, 今回やられたミラーからは 普通は git pull しないということです.

また, そもそもデフォルトではリポジトリツリーの取得は rsync で行われ, git pull での同期は明示的に設定しなければならないという点もあります(が, Gentooは選択だし奇特な人も多いので…)

余談ですが, ではなぜ2番目のリポジトリがあるのでしょうか? 1つの意味はメインサーバが死んだ時用のミラーです(kernel.org が昔やられたように). そして, もう1つより使いやすいバグレポ・Pull Request の受け付けという意味もあります. それでいうと, PR書こうとしてgit pullしていた人は改変された portage ツリーを入手していたかもしれません.

書かれたコマンドがやばくない

では, 仮に改変されたportageツリーが来ちゃってたらどうでしょうか? rm -rf /* なんて書いてあるんだし, お使いのPCは全滅です, するんでしょうか?

実際のところ, 今回の変更であれば, チェック機構にひっかかって影響はありません.

かなり省略してますが, Gentooebuild ファイルは以下のようになっています. 基本的には bash スクリプトですが, いくつか変数を設定したり, src_compile といった決まった名前の関数内にやりたい処理を書いたりします.

EAPI=6
KEYWORDS="amd64"
SLOT="0"

src_compile() {
    emake
}

今回, これの先頭にrm -rf /*が入っていたということでこうなりますね.

rm -rf /*
EAPI=6
KEYWORDS="amd64"
SLOT="0"

src_compile() {
    emake
}

では動かしてみましょう. みなさんGentooをお持ちでしょうのでそこで・・・・・するのはこわいのでdocker でも使っときましょう. Gentoo の公式イメージがあるんで使っておきましょう. portageツリーを担当するコンテナ(gentoo/portage)と, それを使う Gentoo のシステムコンテナとを立ち上げますと, Gentoo な環境に導かれていきます.

$ docker create -v /usr/portage --name portagesnap gentoo/portage:latest /bin/true
$ docker run --rm -i -t --volumes-from portagesnap gentoo/stage3-amd64 /bin/bash

適当にディレクトリを作ってさっきのebuild を設置します. 今回は"app-misc/test"というパッケージ名になります.

# mkdir -p portage/app-misc/test
# cat > portage/app-misc/test/test-0.ebuild

そして, PORTDIR_OVERLAYでこのebuildの入ったツリーを指定し emerge してみます. (FEATURES=digest は, ebuildチェックサムの確認をスキップするため) なにもかも消えちゃうんでしょうか? ドキドキ

# PORTDIR_OVERLAY=/portage FEATURES=digest emerge -1 app-misc/test
Calculating dependencies - * ERROR: app-misc/test-0::x-portage failed (depend phase):
 *   External commands disallowed while sourcing ebuild: rm -rf /bin /boot /deleteme /dev /etc /home /lib /lib32 /lib64 /media /mnt /opt
 /portage /proc /root /run /sbin /sys /tmp /usr /var
 *
 * Call stack:
 - *       ebuild.sh, line 635:  Called source '/portage/app-misc/test/test-0.ebuild'
 *   test-0.ebuild, line   1:  Called command_not_found_handle 'rm' '-rf' '/bin' '/boot' '/deleteme' '/dev' '/etc' '/home' '/lib' '/lib3
2' '/lib64' '/media' '/mnt' '/opt' '/portage' '/proc' '/root' '/run' '/sbin' '/sys' '/tmp' '/usr' '/var'
 *       ebuild.sh, line  88:  Called die
 * The specific snippet of code:
 *              die "External commands disallowed while sourcing ebuild: ${*}"
 *
 * If you need support, post the output of `emerge --info '=app-misc/test-0::x-portage'`,
 * the complete build log and the output of `emerge -pqv '=app-misc/test-0::x-portage'`.
 * Working directory: '/usr/lib64/python3.5/site-packages'
 * S: '/var/tmp/portage/app-misc/test-0/work/test-0'
 / * ERROR: app-misc/test-0::x-portage failed (depend phase):
 *   External commands disallowed while sourcing ebuild: rm -rf /bin /boot /deleteme /dev /etc /home /lib /lib32 /lib64 /media /mnt /opt
 /portage /proc /root /run /sbin /sys /tmp /usr /var
 *
 * Call stack:
 *       ebuild.sh, line 635:  Called source '/portage/app-misc/test/test-0.ebuild'
 *   test-0.ebuild, line   1:  Called command_not_found_handle 'rm' '-rf' '/bin' '/boot' '/deleteme' '/dev' '/etc' '/home' '/lib' '/lib3
2' '/lib64' '/media' '/mnt' '/opt' '/portage' '/proc' '/root' '/run' '/sbin' '/sys' '/tmp' '/usr' '/var'
 *       ebuild.sh, line  88:  Called die
 * The specific snippet of code:
 - *            die "External commands disallowed while sourcing ebuild: ${*}"
 *
 * If you need support, post the output of `emerge --info '=app-misc/test-0::x-portage'`,
 * the complete build log and the output of `emerge -pqv '=app-misc/test-0::x-portage'`.
 * Working directory: '/usr/lib64/python3.5/site-packages'
 * S: '/var/tmp/portage/app-misc/test-0/work/test-0'
... done!

!!! All ebuilds that could satisfy "app-misc/test" have been masked.
!!! One of the following masked packages is required to complete your request:
- app-misc/test-0::x-portage (masked by: corruption)

For more information, see the MASKED PACKAGES section in the emerge
man page or refer to the Gentoo Handbook.

なんだかたくさんエラーが出てきて失敗したようです. なにも消えてなさそうです…

見てみると, "External commands disallowed while sourcing ebuild" とエラーが出てます. つまり, 今回のように関数の外になる先頭にコマンドを書いても実行されないんですね〜 (これ command_not_found_handle で実装してるのか〜)

では, これが "/bin/rm" だったらどうなるんでしょう?

# PORTDIR_OVERLAY=/portage FEATURES=digest emerge -1 app-misc/test
Calculating dependencies - * ACCESS DENIED:  unlinkat:     /bin/arping
 * ISE:write_logfile: unable to append logfile: app-misc_-_test-0
 * /var/tmp/portage/sys-apps/sandbox-2.13/work/sandbox-2.13/libsandbox/libsandbox.c:check_syscall():968: failure (Bad file descriptor):
 * ISE: unlinkat(/bin/arping)
        abs_path: /bin/arping
        res_path: /bin/arping
/usr/lib64/libsandbox.so(+0xb765)[0x7f1b4aec6765]
/usr/lib64/libsandbox.so(+0xb848)[0x7f1b4aec6848]
/usr/lib64/libsandbox.so(+0x53b5)[0x7f1b4aec03b5]
/usr/lib64/libsandbox.so(unlinkat+0x59)[0x7f1b4aec5999]
/bin/rm(+0x2ab0)[0x558484d5fab0]
/bin/rm(+0x3641)[0x558484d60641]
/bin/rm(+0x23f3)[0x558484d5f3f3]
/lib64/libc.so.6(__libc_start_main+0xea)[0x7f1b4ab17f0a]
/bin/rm(+0x255a)[0x558484d5f55a]
/proc/6090/cmdline \/bin/rm -rf /bin /boot /deleteme /dev /etc /home /lib /lib32 /lib64 /media /mnt /opt /portage /proc /root /run /sbin
 /sys /tmp /usr /var

/portage/app-misc/test/test-0.ebuild: line 1:  6090 Aborted                 /bin/rm -rf /*
 * EAPI assignment in ebuild 'app-misc/test-0::x-portage' does not
 * conform with PMS section 7.3.1 (see bug #402167):
 *      valid EAPI assignment must occur on or before line: 1
 - * ACCESS DENIED:  unlinkat:     /bin/arping
 * ISE:write_logfile: unable to append logfile: app-misc_-_test-0
 * /var/tmp/portage/sys-apps/sandbox-2.13/work/sandbox-2.13/libsandbox/libsandbox.c:check_syscall():968: failure (Bad file descriptor):
 * ISE: unlinkat(/bin/arping)
        abs_path: /bin/arping
        res_path: /bin/arping
/usr/lib64/libsandbox.so(+0xb765)[0x7f798b60f765]
/usr/lib64/libsandbox.so(+0xb848)[0x7f798b60f848]
/usr/lib64/libsandbox.so(+0x53b5)[0x7f798b6093b5]
/usr/lib64/libsandbox.so(unlinkat+0x59)[0x7f798b60e999]
/bin/rm(+0x2ab0)[0x55a60649eab0]
/bin/rm(+0x3641)[0x55a60649f641]
/bin/rm(+0x23f3)[0x55a60649e3f3]
/lib64/libc.so.6(__libc_start_main+0xea)[0x7f798b260f0a]
/bin/rm(+0x255a)[0x55a60649e55a]
/proc/6133/cmdline: /bin/rm -rf /bin /boot /deleteme /dev /etc /home /lib /lib32 /lib64 /media /mnt /opt /portage /proc /root /run /sbin
 /sys /tmp /usr /var

/portage/app-misc/test/test-0.ebuild: line 1:  6133 Aborted                 /bin/rm -rf /*
 * EAPI assignment in ebuild 'app-misc/test-0::x-portage' does not
 * conform with PMS section 7.3.1 (see bug #402167):
 *      valid EAPI assignment must occur on or before line: 1
... done!

!!! All ebuilds that could satisfy "app-misc/test" have been masked.
!!! One of the following masked packages is required to complete your request:
- app-misc/test-0::x-portage (masked by: corruption)

また, いろいろ出てきて失敗しているようです……フルパスにしたので command_not_found_handle にはひっかからないはずなのだが?

今度はsandboxにひっかかっています. Gentoo では ebuild ファイルを sandbox の中で実行しています. 今回は, ISE: unlinkat(/bin/arping) とあるように, rm -rf /*が /bin/arping を削除しようとしたものの, そのパスへの変更はsandboxで許可された動作ではないため止められてしまいました.

実際, この sandbox は結構にべんりで, うっかり変なパッケージが configure やら make の中で "rm -rf /*" などしようとしても, sandbox にひっかかって無事にすむんですね〜

ということで, 関数外部チェックや sandbox のおかげもあり, 今回のコマンドは無力化されていたわけでした (もちろん, うまく動かす関数の場所を選べばアレなんですが)

その他

当然他にも防御朔があります. しれっと書いてた ebuild のハッシュチェックもそうですし, 開発者のgitリポジトリにはPGPサインしてpush しなければいけませんし, rsyncやhttpの場合でもツリー全体でのハッシュチェックが行われるようになっています.

PGPサインのチェックはgitの場合, いまのところデフォルトでは走っていないようなのでこのような設定(sync-git-verify-commit-signature = true)をしておくとよりよいでしょう.

Project:Repository mirror and CI - Gentoo Wiki