Linuxの実ユーザIDと実効ユーザIDについて

Linuxには実ユーザIDと実効ユーザIDというのがあります。実ユーザIDとはプログラムを実行したユーザで、プログラムはそのユーザIDの権限で動きます。通常は実ユーザIDと実効ユーザIDは同じになります。

ユーザ「AAA」が所有者「BBB」のプログラムを実行します(AAAが所有していない他人のプログラムを実行します。このプログラムのアクセス権限は「rwxr-xr-x(755)」であるため他人であるAAAも実行することが可能です)。このときこのプログラムはAAAの権限で動くことになります。つまり、AAA所有のファイルにはアクセス可能ですがBBB所有のファイルにはアクセス不可です。ファイルのアクセス権が「rw-rw-rw-(666)」の場合はアクセス可能です。このときの実ユーザIDと実効ユーザIDは「AAA」となります。

実ユーザIDと実効ユーザIDが異なるケースですが、代表例でいうと「su」コマンドや「passwd」コマンドです。これらのコマンドはパスワードの読み取りが必要なのですが、パスワードは「/etc/shadow」ファイルに書かれており所有者はrootでアクセス権限が「rw——-」となっています(※shadowファイルのアクセス権については後述)。つまり、一般ユーザの権限でこれらのコマンドを実行してもshadowファイルにアクセスできません。そこで、実ユーザは一般ユーザだけれども実効ユーザはrootとなる仕組みが必要になります。これを実現するのが「セットユーザIDビット」というもので、このビットをセットすると実行権限が「x」ではなく「s」となりプログラムは実行したユーザの権限ではなくプログラム所有者の権限で動きます。「su」コマンドや「passwd」コマンドの所有者はrootでありセットユーザIDビットが設定されていますので、rootの権限でプログラムが実行されます。以下はubuntuのsuコマンドとpasswdコマンドの権限を表示したものです。

(※)shadowファイルのアクセス権について
Linuxのディストリビーションによって権限が異なるようです。ubuntuの場合は「rw-r—–(640)」、CentOSの場合は「———(000)」となっているようです。CentOSの場合「000」ですが、rootでは読めますので「400」と同じみたいです。

セットユーザIDビットが設定されたプログラム(所有者はBBB)をユーザAAAが実行したときの場合です。

実ユーザIDはAAA、実効ユーザIDはBBBとなるので所有者がBBBのファイルにアクセスが可能となります。

セットユーザIDビットはグループに対しても使うことができ、その場合は「セットグループIDビット」と言います。IDの使われ方も実グループID、実効グループIDとなり、ユーザIDの考え方と同じです。セットユーザIDビット、セットグループIDビットの設定の仕方は以下となります。

セットユーザIDビット
$ chmod u+s ファイル名

セットグループIDビット
$ chmod g+s ファイル名

あと、セットユーザIDビットに似た(?)ものとしてstickyビットというものがあるので書いておきます。stickyビットが設定されたディレクトリ配下では誰でもファイルの作成や書き込みができますが、ファイル削除、ファイル名変更はファイルを作成した所有者とrootのみができるようになる権限です。stickyビットが設定されると実行権限には「t」が設定されます。「/tmp」ディレクトリにはstickyビットが設定されています。stickyビットの設定の仕方は以下となります。

stickyビット
$ chmod o+t ディレクトリ名

Linux上のファイルのOpenとClose処理について考えてみた。

プログラムを実行すると、そのプログラムが扱うファイル情報のための領域が確保されます。この領域はリスト形式で複数個、用意されます。このリストを利用者ファイル記述子表と呼んでいます。C言語でfopen関数を呼ぶとファイルポインタが返りますが、このファイルポインタは利用者ファイル記述子表のどの場所かを示すポインタとなります。またopenシステムコールを呼んだ場合はファイル記述子(ファイルディスクリプターとも呼ぶ)が返りますが、ファイル記述子はリストの何番目かを示す配列の番号です。

※上の絵のfdはファイルディスクリプターの略、fpはファイルポインタの略です。

標準入力、標準出力、標準エラー出力はプログラム実行時に自動的に割り当てられるファイル情報の領域で、ファイル記述子はそれぞれ、0、1、2 と決まっています。通常、標準入力はキーボード、標準出力、標準エラー出力は端末の画面となります。

ここで新規にファイルを作成する場合を考えてみます。ファイル記述子は3以降が使われます。openシステムコールを新規作成で呼ぶと以下の領域が確保されます。

  • プログラム内のファイル記述子表に新規ファイル分を追加
  • ファイルシステムのiノードリストに新規ファイル分を追加
  • ファイルアクセスのための入出力用バッファを用意

絵に書くと以下のような感じです(iノードについては前回前々回を参照ください)。

ファイルのOPENにより利用者ファイル記述子表とiノードリストの紐付けを行っています。これによりファイル記述子からファイルのアクセス権の設定やファイルの読み出し/書き込みが行えることになります。またファイルのCLOSEを行うことにより利用者ファイル記述子表とiノードリストの紐付きを解除しています。

ちなみに、別々のプログラムが同一ファイルをOPENして読み書きを行う場合(共通のログファイルへの書き出しなど)は以下のような絵になると思います。

同一ファイルへのアクセスでも利用者ファイル記述子表のファイル記述子は(プログラム内で保持するため)別々のものとなります(たまたま同じになるときももちろんあります)。