rm -rf /
やったことある人。
私はないです。
以下はAndreas Müller( Twitter / GitHub / LinkedIn / Medium )による記事、9 Evil Bash Commands Explainedの日本語訳です。
9 Evil Bash Commands Explained
初めてターミナルを使って、そしてそれを理解したときのことを覚えています。
あらゆるファイルにアクセスし、全てのプログラムを実行し、黒い画面に何かを入力するだけでシステムの全てを完全に掌握できることに気がついた、あの感覚。
そしてもちろん、致命的ミスを犯して全てを失った、あのときの恐怖も。
私は本当はシステム管理者ではありませんが、長年にわたってLinux/UNIXベースのシステムで作業してきたので、コマンドを実行しようとしてEnterキーを打つことを躊躇う状況に何度も遭遇しました。
以下では、全く出番がないか、あるいは非常に慎重に実行する必要のあるコマンドを紹介します。
bashコマンドを使ったことがないのであれば、何か新しいことを学べることを祈っています。
あなたがbashのプロであれば、解説を読む前に、どんな結果が起こるか予測してみましょう。
コマンドの多くは実体験を通じて習得したものですが、これらの多くは別の投稿でも見ることができます。
最後の警告です。
⚠重要なシステムでこれらのコマンドを実行してはいけません! ⚠
1. Destructive directory changing
古典中の古典であるrm -rf /*
ではなく、そのバリエーションから始めましょう。
alias cd='rm -rf'
💡 That's what happens
・alias
コマンドは、エイリアスやショートカットを宣言するbashコマンドです。
構文はalias alias_name="command_to_run"
のようになります。
・cd
はchange directory
の略です。
・rm -rf
は実行するコマンドです。これは決して"read mail, -realfast"という意味ではなく、指定されたディレクトリ内の全てを警告なしに削除するという意味です。
あなたが少し席を外した隙に、悪意ある人物が開いたままのウィンドウにわずかな文字列を入力することができたとしたら、あなたはディレクトリを移動しようとしたあとで深い絶望に襲われることでしょう。
幸いalias
コマンドは、ターミナルのセッション開始時に読み込まれるファイル(~/.bashrc
など)に登録されないかぎり、現在開いているセッション内だけでしか有効ではありません。
🛡 How to prevent possible damage
新しいエイリアスを追加する際は、単に追加するのではなくその前に再確認が必要です。
alias
で現在のエイリアスを確認することができ、そしてunalias alias_name
で既存のエイリアスを削除することができます。
いつのまにかファイルが削除されることを防ぐために、~/.bashrc
に以下のエイリアスを追加することができます。
alias rm='rm -i'
これにより、何か別のコマンドのエイリアスとしてrm
コマンドが仕込まれていた場合でも、削除する前に確認してくれます。
※ 一応言及しておきますが、このコマンドではそう簡単に壊せません。
ルートディレクトリでの実行には--no-preserve-root
オプションが必要になりました。
2. Memory-eater
信じられないかもしれませんが、以下は正当なbashコマンドです。
:(){:|: &};:
💡 That's what happens
簡潔に言うと、終了条件なしの再帰です。
まず:
という関数を定義します。
これは関数内で自身を2回呼び出しています。
最後の:
で最初の関数呼び出しをしています。
すなわち、わかりやすく記述すると以下のようになります。
evil () {
evil|evil &
}
evil
これはFork爆弾とも呼ばれ、実行すると全てのメモリとCPUリソースをすぐに使い果たします。
システム全体がフリーズする可能性もある、DoS攻撃の一例です。
わずか12バイトのコマンドでこのような攻撃が実行できるとは、驚くべきことです。
🛡 How to prevent possible damage
繰り返しや再帰するbash関数を使っている場合は、適切に終了するように条件を確認し、切り離されたテスト環境で実行してください。
Fork爆弾はプロセスを無制限に起動するため、システムを保護する唯一の方法は、ローカルユーザが実行できるプロセスの数を制限することです。
それは/etc/security/limits.conf
を編集することで実現できます。
ユーザ一人あたり200から300程度のプロセスを同時に使用するため、全体で2000プロセス程度に制限すれば、締め付けを厳しくしすぎることなくシステムをFork爆弾から保護することができるでしょう。
3. Zero memory
dd if=/dev/zero of=/dev/sda
💡 That's what happens
dd
は、あるファイルやデバイスなどから、別の何らかにデータをコピーするコマンドです。
if=
にはコピー元のファイル/デバイスを指定し、そして/dev/zero
はnullで埋め尽くされた無制限のリソースです。
of=
にはコピー先のファイル/デバイスを指定し、そして/dev/sda
はディスクドライブです。
まとめると、これはディスク全体を消去する優れた方法であり、大量のデータを失うための迅速な手段です。
🛡 How to prevent possible damage
残念なことに、rm
にあった-i
のようなオプションは存在しません。
dd
コマンドで指定するデバイスが本当に正しいものであるか確認するしかありません。
リスクがある場合は、dd
コマンドを使用しないでください。
alias dd='echo "no dd command available"'
このエイリアスを登録しておけば、dd
コマンドは動作しなくなります。
4. Zero recovery
上記コマンドのバリエーションも考えられます。
for i in {1..10};do dd if=/dev/urandom of=/dev/sda;done
💡 That's what happens
これによって、ディスク全体がランダムバイトで10回上書きされるため、データを復旧される可能性がさらに減少します。
🛡 How to prevent possible damage
これもdd
コマンドを使用しているため、回避策は上の項目と同じです。
5. Uncommitted and lost
git reset --hard
💡 That's what happens
git reset
は、gitリポジトリのHEADを、最後にcommitした時点にリセットします。
--hard
はワーキングツリーをリセットします。
最後のcommit以降にワーキングツリーで行われた変更は破棄されます。
言い換えると、commitしていないあらゆる変更が消滅します。
gitはそれらを追跡していないため、復元する方法はありません。
🛡 How to prevent possible damage
単純に--hard
オプションを使わないようにしましょう。
使わなければならなくなった際は、保存しておかねばならないローカル変更が存在しないかを確認します。
git status
の出力が空であるか、commitしていないデータを全て確実に削除したいという場合にのみ、ハードリセットを行うことをお勧めします。
6. Demolition by compression
tar -czvf /path/to/file archive.tgz
# ↓のつもりで間違えた
tar -czvf archive.tgz /path/to/file
💡 That's what happens
tar -czvf
は、新しいアーカイブを作成し、gzip圧縮し、詳細を画面に出力し、アーカイブを指定したファイルに出力します。
archive.tgz
は出力するファイル名です。
/path/to/file
は圧縮する対象のパスです。
この順番は重要です。
圧縮したいファイルをひとつめに持ってきてしまった場合、tarはそのファイルを上書きしてアーカイブの作成を開始し、その後で2番目に指定されたファイルを見に行ってそれが存在しないことに気付くため、最初のファイルは破壊されます。
これは、ファイルのバックアップを作成しようとして引数の順序を間違えた場合には、特に深刻です。
🛡 How to prevent possible damage
全てのオプションを一括指定するのではなく-f
オプションだけ分離し、またロングオプションを使うことでわかりやすくなります。
tar -czv --file archive.tgz /path/to/file/to/compress
7. Too many rights
chmod -R 777 /
# ↓のつもりで間違えた
chmod -R 777 ./
💡 That's what happens
chmod -R
はファイルのパーミッションを再帰的に変更します。
777
はパーミッションの指定で、あらゆる操作を許可します。
./
は変更対象のディレクトリもしくはファイルです。
対象ディレクトリとしてうっかりルートディレクトリを指定してしまうと、システム全体の権限が壊れてしまい、再起不能になります。
🛡 How to prevent possible damage
chmod
には--preserve-root
が指定可能です。
alias chmod='chmod --preserve-root'
これにより、ルートディレクトリからの再帰的chmodは拒否されます。
8. The root of all evil
所有者の変更にも同じ間違いが起こり得ます。
chown -R root:root /
# ↓のつもりで間違えた
chown -R root:root ./
💡 That's what happens
chown -R
は所有者を再帰的に変更します。
root:root
は所有者とグループの指定です。
./
は変更対象のディレクトリもしくはファイルです。
このコマンドはシステムの再インストールが必要になる可能性の最も高い方法で、あらゆるファイルを台無しにします。
🛡 How to prevent possible damage
対処方法もchmodと同様です。
alias chown='chown --preserve-root'
これにより、ルートディレクトリからの再帰的chownは拒否されます。
9. Encrypted and destroyed
fsck -y /dev/sda
💡 That's what happens
fsck
はファイルシステムのチェックを行います。
-y
は、検出されたファイルシステムの破損を自動的に修正するオプションです。
/dev/sda
はチェック対象のボリュームです。
これは良いことです。
ただし、ボリュームが暗号化されている場合を除いてですが。
暗号化されているボリュームにfsck -y
を実行すると、完全に破壊されます。
🛡 How to prevent possible damage
暗号化されていない通常のボリュームであることが確実である場合にのみ、fsck
を使用するようにしてください。
Wrap it up
ちょっとしたコマンドを打つだけで、データを破壊したりシステムを再起不能にしたりすることは非常に簡単だということがわかりました。
結論として、最善の方法は、何かを実行する前に入力内容を把握し、タイプミスを再確認することです。
コマンドをコピペすることではありません。
bashコマンドについては真実かもしれませんが。
また、常にバックアップ体制も整えておきましょう。
上記コマンドのほとんどは完全に動かすにはroot権限が必要です。
そのため、rootで作業するときには特に注意してください。
他に邪悪なコマンドを知っている人は、是非コメントで共有してください。
免責事項:上記コマンドを試してシステムに損害を与えた場合、私は責任を負いません。
テストには仮想マシンのような安全な環境を使用してください。
注意はしましたよ。
コメント欄
「最上部に注意書きを置いた方がいい。」「ありがとう追加した。」
「BOFH思い出した。」「同じこと思った。」
「4をもっと高速に強化してみた。openssl enc -aes-256-ctr -pass pass:"$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64)" -nosalt </dev/zero > /dev/sda1
」
「echo o > /proc/sysrq-trigger
。メモリ使用量について文句ばっかり言ってくる同僚がいるときに最適。」
「findのオプションの順番間違いとか。find -name "file-to-delete" -delete
と書くつもりでfind -delete -name "file-to-delete"
としちゃったなど。」
「いちどrm -rf /etc
ってやっちゃったことがある。同じ構成のサーバがもう一台あったので幸い復旧できた。」
「昨日コマンドのひとつを試してみた。今日、この投稿はヤバいと言いに来た。」
「5はgit reflog
で復旧できない?」「commitしてないからreflogはできないはず。でもaddしていればgit fsck --lost-found
で復旧できることがわかったよ。」
「この記事を投稿するのは悪い考え。最高のセキュリティは誰にも言わないことだ。」「それには同意できない。セキュリティ問題と予防の可能性について議論することは不可欠だ。」
「先日evil.shを見かけて意味がわからなかったFork爆弾が理解できたよ。」
「alias dd='echo "no dd command available"'
は完全に安全ではないよ。\dd if=/dev/zero of=/dev/sda
でまだ呼び出せる。」「本当だありがとう。完全に無効化する提案はありますか?」「エイリアスとかで回避するよりも危険なコマンドについて啓蒙すべき。」
「コマンドの先頭に\
を付けるとaliasを無視するのだ。」
「rm -i
は強固な保護だとみなされてるけど、実際はそうとも限らない。」
mkdir experimental-directory
cd experimental-directory
touch very-important-file
touch ./-f
# 一括削除したいがvery-important-fileだけは消したくないのでrm -iするのだ
rm -i *
ls
# あれ?
感想
crontab -r
はやったことがある。
evilなコマンドと言いつつ、うっかりミスによる事故も混ざってるのでタイトルに違和感がありますね。
本当に邪悪なコマンドだけに振り切るか、タイトルを少し変更してほしいところではあります。
あと回避策のところ、alias
でエイリアスを確認しろとか書いてあるけど、alias alias="rm -rf / --no-preserve-root"
みたいな文も書けるはずなので(試してない)、その後普通にエイリアスを確認しようとしたら死にます。
\alias
って書いた方がいいですね。
何か仕掛けられている可能性があるなら、aliasを無視する\
付きコマンドを使いましょう。
もっとも毎回そんなことやってられませんし、そもそもロックをかけずに離席してる時点でアウトですが。
Linuxコマンドはゴミ箱やundoなどの安全装置が基本的にないため、たった一度のうっかりが致命的になることがよくあります。
私は重要作業は事前にテキストに書き出してSlack/Redmineで共有みたいなことはやっていますが、日々のちょっとした作業などは大抵そのままやってしまっています。
しかも普段は一般ユーザとはいえ、時折rootも使ったりしますからね。
私が今まで大きな事故をやらかしてないのは運が良かったからに過ぎないでしょう。
この手のうっかり事故を完全に防ぐにはどうすればいいのでしょうかね。