Article 3995 of fj.unix: Path: news2.sra.co.jp!katsu From: katsu@sra.co.jp (WATANABE Katsuhiro) Newsgroups: fj.unix Subject: Re: 史上最悪の事態(実話) Date: 7 Oct 1998 07:07:04 GMT Organization: Software Research Associates, Inc., Japan Lines: 423 Message-ID: <6vf3uo$mbs$1@sranhh.sra.co.jp> References: <659i3u$bs9$1@psyche.rcep.dpri.kyoto-u.ac.jp> <65n7rn$g7a$2@news2.na.rim.or.jp> NNTP-Posting-Host: sras49.sra.co.jp In-reply-to: TSUMAI Yasuyuki's message of 23 Nov 1997 15:29:02 GMT Originator: katsu@sras49 Xref: news2.sra.co.jp fj.unix:3995 あまりのフォローの遅さが議論の妨げになっていたらごめんなさい。 root で rm -r / を実行した後どうなるかに関して、特にカーネルの ファイルが失われる点に焦点を当てて考えます。 > From: railer@rcep.dpri.kyoto-u.ac.jp (TSUMAI Yasuyuki) > Message-ID: <659i3u$bs9$1@psyche.rcep.dpri.kyoto-u.ac.jp> > Date: 23 Nov 1997 15:29:02 GMT > | >> ところで root で rm -r / を実行した後はどうなるのでしょう? > | > | UNIX でそういう経験はありませんが、パソコン(MS-DOS)において、 > | C:\ で del * をやってしまった人を知っています。その時は com > | の中にある del コマンドが消える途中で動作が止まりました。 > | おそらくそれと似たようなことになるのではないかと思います。 > > ならないでしょう。DOS で del コマンドが消えると動作が止まる > というのも怪しいですが、del コマンドがワイルドカード(*)を展 > 開しているからでしょうか? UNIX では、ワイルドカードの展開は > シェルが行います(展開してからコマンドに渡される)。 > > それより、カーネルが消えたときに... 妻井 消えた時に何か起きるというのでしょうか?カーネルの reconfig や recompile の時など、カーネルのファイルが消されることはあります。 私自身、種々のシステムで実際に消してみていますが、その時点で 変な現象に遭遇した経験もありません。また、Linux に限ってですが、 何も起きないという実験結果を、[RMRF2] "What happens if root does "rm -rf /"?"; http://www.sra.co.jp/people/katsu/doc/rmrf/ において参照いただけます。 典型的な UNIX における通常の結末を確認しておきます。 1. reboot するには、代替のカーネルを指定する必要がある。 2. カーネルシンボルテーブルを参照するコマンドは動かなくなる。 3. カーネルは動き続ける。なぜならば... 3.1 カーネルは普通 demand paging/page out されない。 3.2 (想像)paging する UNIX を実装してみても、inode(vnode) を 通じて参照するはずで、unlink しても中身は残ったままになる。 1. 自明でしょう。 2. カーネルファイルからシンボルテーブルを取り出して変数を参照する プログラム(古典的な UNIX では ps(1), uptime(1) など)は正常に 動かなくなります。ただし、近年の UNIX の傾向として、カーネルの 変数を直接参照する場面は減少してきていると感じます。 /dev/kmem 経由のカーネル変数の参照という低レベルのものが、 ・ /proc ファイルシステム(多くの UNIX) ・ kernel ファイルシステム(4.4BSD) ・ sysctl(3)(4.4BSD) ・ kstat(3)(SunOS) ・ sysinfo(2), sysconf(3)(SunOS) など、カーネルの活動に関する情報を提供する抽象度の(比較的)高い インターフェースで置き換え可能になっている場合が増えています。 この結果、カーネルのファイルが消えて影響が受けるコマンドは (とりわけ標準のものでは)減少しているはずです。 加えて、最近の OS では、 ・カーネルのファイルのパスをユーザプロセスでは決定できない。 ・動的にモジュールをロードする仕組みのせいで、カーネルの空間を  形成するファイルはもはや単一ではなく、変数の存在が動的に定まる  ことが多い。 ・SunOS の /dev/ksyms のようなシンボルテーブル専用のデバイスが  用意されている場合がある。 ・compression などの理由で、カーネルファイルのフォーマットが  NMAGIC や ZMAGIC のような単純な形式でなく、テーブルを素直に  得られない場合がある。 という事情もあって、カーネルが起動してしまった後にカーネル ファイルからシンボルを取り出すことの必要性や妥当性はますます 薄れている印象を持っています。(BSD の場合については、[BSD44] p.509 "Passage Information To and From the Kernel" に、多少の 議論があります。) 3. 3.1 普通カーネルの text segment や data segment 等は、demand paging や page out の対象外です。(ヒープなどは paging の対象になり得ます。) これは、最近の UNIX においてデバイスドライバやカーネルモジュールを 動的に load する場合においても、おおむね言えると思います。(反例を ご存じの方は、ぜひ教えてください。)カーネルやデバイスドライバの bottom half(から参照される何らかのデータ)が page out される 場合や、仮想記憶システム自身の paging を考えれば、text seg, data seg の paging が難しい理由の1つを直感的に理解してもらえる でしょうか。 (demand paging ではなく、load on demand: デバイスに最初にアクセス する時までモジュールの load を遅延させることはよく行われていると 思います。) paging しない根拠もあげておきます。参考文献 [UI] p.372 は、 UI> When the system boots, the kernel reserves part of physical UI> memory for its own text and static data structures. This UI> portion is never released and hence is unavailable for any UI> other purpose.*1 UI> *1 Many modern UNIX systems (AIX, for instance) allow part of UI> the kernel to be pageable. とカーネルが常駐するとの説明があります。(ちなみに AIX でも、 ここでの議論の焦点 "rm" をしても、全然問題ではないことでしょう。 これは 3.2 で考えます。) 以下、具体的なシステムをいくつか取り上げてみます。 まず BSD を見ると、文献 [BSD44] p.179 には BSD44> Unlike a user process that is demand paged into memory, BSD44> the text and data for the kernel are read into memory in BSD44> their entirety. と、demand page しないと言明し、さらに p.137 で BSD44> After the physical memory that will be dedicated to the BSD44> kernel itself has been deducted, all the remaining pages BSD44> of physical memory are described by vm_page structures. とカーネル自身の領域が paging の領域から外されると明記しています。 #ifdef 余談 4.3BSD まではカーネルの magic は NMAGIC(demand paging しない ことを意味)でした。もちろん、カーネルファイルを読むのは boot loader であり、execve(2) されることは決してないので、カーネル ファイルの magic がカーネルの仮想記憶システムと何か関係を 持つことはないでしょう。それでも、象徴的なものを感じます。 #endif /* 余談 */ SVR4 の場合は、文献 [MAGIC] の p.80 に MAGIC> ・カーネルテキスト(kernel text) --- ほとんどのシステムの MAGIC> カーネルはすべて物理メモリに永久に常駐する。 MAGIC> ・カーネルデータ(kernel data) --- カーネルが起動すると、 MAGIC> カーネルの静的データのために物理メモリの領域が予約される。 MAGIC> このメモリ領域は物理メモリに永久に常駐する。 と言明されています。 SunOS 4.X, 5.X の場合は、文献 [SOLARIS] の p.209 に SOLARIS> ほとんどのカーネルページはつねにメモリ中に存在する。 という記述があります。また、文献 [SUNWORLD] の "Kernel memory" という節には、 SUNWORLD> Kernel memory is normally locked and cannot be paged out SUNWORLD> in a memory shortage, but the kernel does free memory if SUNWORLD> there is a lot of demand for it. Unused device drivers SUNWORLD> will be unloaded, and unused slabs of kernel memory data SUNWORLD> structures will be freed. と、主記憶上に固定されないのは、不用のデバイスドライバや不用の データ(多分動的にとられたデータ)であることを述べています。 なんでも、paging が激しくなるとスピーカーが「プツ」と言うとか... 以下、例外的な事例も挙げてみます。 NeXT では、loadable kernel server の text コードなどは wire しなくても(unwire しても)よいようです。しかし、文献 [NEXT] p.A-5 は NEXT> WIRE Causes the text and data of the loaded kernel server NEXT> to be wired down (memory-resident), making the kernel NEXT> server immune from unexpected page faults. You must NEXT> use WIRE if any part of your kernel server can be NEXT> called from an interrupt handler. という条件をつけており、bottom half での paging を嫌っています。 loadable server で駄目なぐらいだから UNIX サーバ部も駄目だろう という推測はありうるでしょう。 AIX の場合も同様のようで、文献 [AIX1] には、 AIX1> * kernel code and data that is not pinned is paged into AIX1> system RAM from a paging logical volume on disk AIX1> + routines that are to be collectively pinned are the AIX1> "bottom half" AIX1> + routines that are not pinned are the "top half" of AIX1> a driver という記述があり、加えて文献 [AIX2] Chapter 2 "System Calls" では、 AIX2> Page Faulting within System Calls AIX2> AIX2> Attention: A page fault that occurs while external AIX2> interrupts are disabled results in a system crash. AIX2> Therefore, a system call should be programmed to ensure AIX2> that its code, data, and stack are pinned before it AIX2> disables external interrupts. AIX2> AIX2> Most data accessed by system calls is pageable by default. AIX2> This includes the system call code, static data, dynamically AIX2> allocated data, and stack. ... と、割り込みも関係することを述べています。   注:    ・wire, wire down, wired 等 --- ページを物理メモリに     「結わえ付け」て常駐させること。あるいは常駐してる状態。    ・pin --- ページを物理メモリに「釘付け」すること。   であり、pin は wire と同じ意味。 ここでみたように、Mach や AIX では、top half で割り込みを禁止して なければ、カーネルの text, static data の一部を paging してよく、 実際にもしているのでしょう。 Mach の上の UNIX サーバ部および Mach カーネル自身、AIX の nuclear system は paging されるかどうかは不明です。Mach をお使いの方の 解説が期待されるところでしょう。 ちなみに、FreeBSD のように、動的にロードされるモジュールでも、 text seg, data seg は paging しないとわかっている(ただし 2.2.5-RELEASE 現在)システムも存在します。動的にロードできる 柔軟さと paging とが相互に関連する傾向は、現在は読み取れません。 なお、paging ではありませんが、非常に古くに PDP/11 の セグメントの制限が非常に小さかった時代、カーネルの overlay を していた UNIX は存在していました。(see. [BSD43] p.115) では、pin や wired down されない loadable server のファイル、 Mach や AIX の nuclear 部等を unlink したら何が起きるか? と思うかもしれませんが、これは次の 3.2 で考えます。 3.2 仮に、ユーザープロセス同様に、カーネルの text seg や data seg も demand paging/page out の対象であるような進歩的な UNIX の実装が あったとしましょう。(3.1 で述べたように、AIX や NeXT は一部 そういう側面がある。)まず、ユーザープロセスの場合がどうだったか 確認しておくと、実行中のコマンドのファイルを unlink(2) しようと したならば、 ・[System V 系統] そもそも unlink(2) が ETXTBSY になってできない。 ・[その他] unlink(2) しても、ファイルの中身が参照でき、問題ない。 でありました。結論として、カーネルについても全く同じ振舞いが 見込まれます。 UNIX では、ファイルへの link (ディレクトリエントリ)が消えるのと、 ファイルの実体(on-disk inode および参照されるディスクブロック)が 消えるのは別であることを思い出してください。仮想記憶システムは、 実装が病的な場合を除き、paging 対象の object を inode(vnode) で 参照するでしょう。カーネルが paging の対象であるとの仮定ですから、 仮想記憶システムが、カーネルファイルの in-core inode(vnode) を 参照しており、参照数は 0 でなくなっているはずです。そういう状況で unlink(2) をしても、in-core inode, on-disk inode 及びディスク ブロックは当然解放されない(か、System V 的に ETXTBSYになる) でしょう。というわけで、病的な実装を選ばない限り、たとえ カーネルの demand paging/page out をする UNIX を実装しても、 カーネルファイルの unlink(2) で特に問題は起きないと想像できます。 一方この種のシステムでは、カーネルファイルを上書きすることで、 システムを crash, panic, or down させられる *可能性* が出てきます。 diskless システムなどで、network の先にファイルが置かれている場合に カーネルを paging したら、性能に大きく影響するという心配もあります。 次に、”rm -rf /" では起こらない事柄ですが、カーネルのファイルの 上書きについて議論します。 > From: hironobu@SpamEater.h2np.suginami.tokyo.jp (Hironobu Suzuki) > Message-ID: > Date: 25 Nov 1997 16:52:37 +0900 > むかし、むかし、もう10年以上むかしのことです。ソニーのNEWSがまだ販売 > される前のことです(笑)。 > > それは、手元にあって僕がほとんど占有して使っていた会社にあるMicroVAX > IIのOSを4.2BSDから4.3BSDにあげる時のことでした。もちろん当時のリールの > ような、適当なテープデバイスがあるわけでもなく、ネットワークで繋がれて > いるだけなので、どうやってアップデートしようかと悩んでいたんです。 > > 先輩達は、手塚さんと同様に、悪魔のようにUNIXを隅々まで知り尽くしている > 人ばかり。そこでのアイデアは、「どうせディレクトリ構造は同じなので、ネッ > トワーク経由で必要なものを全部上書きする」という大胆なものでした。どう > せ失敗しても、僕のマシンだしと思っていたに違いありませんけど。 > > で、問題は、動作中のコマンドやカーネルです。当然、上書きできません。 コマンドは別として(記事 [RMRF] で議論しました)、カーネルは 上書き(書き込みでの open(2), truncate(2) 等)できるはずです。 ETXTBSY が起きたりしません。なぜなら、カーネルのファイルは execve(2) されていないからです。(ちなみに、テキストテーブルが あるような伝統的 UNIX でも、テーブルにカーネルは載っていません でした。興味があれば、テキストテーブル関連の記事 [TEXTTABLE] http://www.sra.co.jp/people/katsu/article/#texttable をご参照あれ。) 以下、カーネルの上書きに関して、実際の例を3例紹介します。 例1: 少なくとも過去においては、adb -w /vmunix でカーネルファイルを 上書きするのは、カーネルへのパッチ当ての標準的な方策でした。 /vmunix を参照している何者かへの配慮が必要であったならば、 % mv /vmunix /vmunix.old; cp /vmunix.old /vmunix % adb -w /vmunix のようにしなければならないはずですが、実際はその必要は全くなく、 % cp /vmunix /vmunix.old % adb -w /vmunix でも何ら問題がありません。実際いくつかのパッチ当て指示書では 後者の記述がみられます(see. [CP])。 #ifdef 余談 私個人は、ファイルのコピーを取るときには、 % mv file file.old; cp file.old file とすることが多いです。ファイルの中身のみならず、on-disk inode の情報も file.old に関連づけられて保存されるからです。 stat(2) した時に st_ctime や st_mtime が保存されていて嬉しい ことは度々あるでしょう。 #endif /* 余談 */ 例2: comp.sys.sun FAQ の中の、カーネルの reconfig に関する説明には、 FAQ> 8) cp /vmunix /vmunix.save FAQ> 9) cp vmunix /vmunix という記述が見られます。 例3: 時代はずっと後ですが、SunOS 4.0.3 か 4.1 ぐらいの時に、技術的な 未熟さが原因で、カーネルのファイルを上書きしてしまったことが ありました。翌日にデモンストレーションを控え、会場で Sun の ネットワークの設定をしていた夕刻のことです。うまくいって、別の UNIX マシンとの間との通信で性能が出ていることを確認しようとし、 ftp> bin ftp> get /vmunix /dev/null とするつもりが、あろうことか root のまま ftp> get /vmunix としてしまったのです。つまり、カーネルのファイルが別の機械のもので 上書きされてしまいました。手元に OS のテープもテープドライブもなく、 復活のしようがありません。予備や古いカーネルも置いてありません。 shutdown してしまっては2度と立ち上がらないことでしょう。しかし、 デモ会場の電源が決して落ちないことを確認し、マシンを起動したままに するよう関係者に強く要請して、そのまま帰りました。翌日は、計算機 資源を酷使するデモプログラムが、カーネルのファイルがないままに、 丸1日きちんと動いていました。 #ifdef オヤジギャグ  今考えるに、この局面では Murphy の法則が顔を出し、   「OS が panic するまでの平均時間: MTBF は1日以下に下がる。」  ことが起きていたものと疑っています。「平均時間」で本当によかった。 #endif /* オヤジギャグ */ > From: dohzono@hf.rim.or.jp (Kazuo Fox Dohzono) > Message-ID: <65n7rn$g7a$2@news2.na.rim.or.jp> > Date: 27 Nov 1997 23:57:25 GMT > In article > hironobu@SpamEater.h2np.suginami.tokyo.jp (Hironobu Suzuki) writes: > > > で、問題は、動作中のコマンドやカーネルです。当然、上書きできません。 > > FreeBSD だと (少なくともコマンドは) できちゃいます. FreeBSD は 4.4BSD の子孫であり、動作中のコマンドを(unlink は できても)上書きはできないはずです。上書きできるのは SunOS でしょう。(詳しい議論は [RMRF] で行いました。) 逆に、既に述べたように、多くの UNIX でカーネルは上書きできます。 ただし、FreeBSD についての話をするとこれが例外の1つです。 4.4BSD の子孫の UNIX では、chflags(2) で schg という変更削除を 抑制する属性をつけることができるため、カーネルファイルを削除 できない場合があります。ただ、これも、カーネルの make 時などに chflags(1) されるという話であり、 ・それが「動作中」であること ・それが動作中の現「カーネル」であること とは、あまり関係がないと思います。 参考文献 [AIX1] "Writing AIX Device Driver"; http://www.developer.ibm.com/library/ref/aixdrv/aixdrv_1.html [AIX2] "AIX Version 4.3 Kernel Extensions and Device Support Programming Concepts"; http://www.rs6000.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/kernextc/toc.htm [BSD43] "The Design and Implementation of the 4.3BSD UNIX Operating System"; Samuel J. leffler, et al.; Addison Wesley; 1989; ISBN 0-201-06196-1; [BSD44] "The Design and Implementation of the 4.4BSD Operating System"; Marshall Krik McKusick, et al.; Addison-Wesley; 1996; ISBN 0-201-54979-4; [CP] 各種サーチエンジンによる "cp /vmunix" や "mv /vmunix" の検索結果 [MAGIC] "UNIX カーネルの魔法"; バーニーグットハート, ジェームスコックス著; 櫻川貴司監訳; プレンティスホール出版; ISBN 4-931356-04-4; [NEXT] "Writing Loadable Kernel servers"; NeXT Developer's Library 内; [RMRF] Subject: Re: 史上最悪の事態(実話); Message-ID: <6veord$l6h$1@sranhh.sra.co.jp>; From: katsu@sra.CO.JP (WATANABE Katsuhiro); http://www.sra.co.jp/people/katsu/article/396.txt [RMRF2] "What happens if root does "rm -rf /"?"; 渡邊克宏; http://www.sra.co.jp/people/katsu/doc/rmrf/ [SOLARIS] "SPARC & Solaris パフォーマンスチューニング"; Adrian Cockcroft 著; 日本サン・マイクロシステムズ監訳; アスキー; ISBN 4-7561-0311-1; [SUNWORLD] "SunWorld - The memory go round - May 1997"; Adrian Cockcroft; http://www.sunworld.com/sunworldonline/swol-05-1997/swol-05-perf.html [TEXTTABLE] "Katsu's news artile" 内のテキストテーブルについての記事; 渡邊克宏; http://www.sra.co.jp/people/katsu/article/#texttable [UI] "UNIX internals: the new frontiers"; Uresh Vahalia; Prentice Hall; 1996; ISBN 0-13-101908-2; -- 渡邊克宏@SRA