fchmod() の謎 |
||
SunOS 4.1.4 | YAMAMORI Takenori |
UNIX で通常、ファイルのパーミッションを変更するには、chmod コマンドを使いますが、chmod コマンドは、内部で chmod() というシステムコールを行なっています。 ファイルのパーミッションを変更するシステムコールには、この chmod() のほかに、fchmod() もあります。chmod() は、ファイル名を引数とするのに対し、fchmod() はファイルディスクリプタを引数とする点が異なっています。 したがって、プログラム的には、すでに open() しているファイルについては、chmod() よりも fchmod() の方が呼び出しやすいという側面もあります。
fchmod() は、後述のように、/bin/cp -p でファイルをコピーする際に、元のファイルのパーミッションを設定するために呼び出されています。
次のように、/bin/cp を用いてコマンドを実行するとカーネルが panic します。
$ /bin/cp -p /bin/cp /dev/audio BAD TRAP .... kernel read fault at addr=0xc, pme=0x0 ....
なお、GNU fileutils に含まれる cp の場合は、内部で fchmod() を使っていないので問題は発生しません。 この現象を再現するには、SunOS 標準の /bin/cp を使う必要があります。
そのほか、自分で問題のデバイスファイルを open() し、fchmod() するような簡単なCソースを書いても症状が再現します。
/bin/cp -p を用いる方法では、デバイスファイルに書き込み permission が必要ですが、問題のバグには書き込み permission は 関係無く、ファイルが open() さえできれば、fchmod() で panic します。
カーネルのソースコードが無いので直接原因を究明できませんが、 panic 時に表示されるアドレス等の情報から、どうやら、VFS オペレーションの fchmod() の処理の部分で、操作対象の(デバイス)ファイルを含むファイルシステムが Read Only で mount されているかどうかをチェックしようとしていて、その Read Only かどうかを示すフラグへのポインタの処理が不適切で、/dev/audio などの一部のデバイスファイルでは何故かポインタが NULL ポインタになってしまっており、その部分で不正なアドレスをアクセスして kernel panic するらしい・・というあたりまで解りました。
/dev/audio や /dev/cgsix0 等の問題のデバイスを外し、 kernel を再構築すればとりあえず問題は防げます。これはサーバー専用マシンなどで /dev/audio や /dev/cgsix0 等を使わない場合の消極的な解決と言えるでしょう。
/dev/audio や /dev/cgsix0 を使いたい場合は依然、問題は未解決のままです。 現状、patch は出ていません。おそらく、バグはプログラム的にはほんのちょっとしたことであり、デバイスドライバの本質に関わるようなものではないと思われます。 しかし、ソースコードがないとどうすることもできません。 このバグも、以前の tmpfs のバグと同様に、いつかきっと解決してやろうと思っています。