疲れた…

一日中読んでました。半日か。前半寝てたし。未読投稿数 79 て。
でも一時的にも活気が戻ったみたいで嬉しい。この後も私が質問とか投げまくるとある程度は持続できるのかな? 尤もこういう抽象的な議論ばっかり続くのも困るわけですが。
ということで再び覚え書き。Hurd っちゅうか OS design ですな。

uid vs capability

Capability を使うと何が嬉しいのかもう一つわかってなかったけど、Jonathan Shapiro が説明してくれたおかげで非常によくわかった。というか、どれも読んだことがあるものばっかりだけど、イメージが湧かなかった。「他人に説明できなければわかったとは言えない」ので、誰にともなく説明してみませう。将来 Guid to Hurd みたいなのを書くことがあれば役に立つかも知れんし。

Computer system S があります。その user の一人を U とします。簡単のために、U は S 上で複数の人格を使い分けないものとします。つまり、normal user として login とか、admin (root) として login とか account を使い分けないということ。

U には S 上で許可される operation があります。どの file を読めるとか、network を使えるとか何とか。何が許されるかは管理者や他の利用者と交渉して決めますが、最終的に「許される operation の集合」というのが決まります。これを A (Authority) とします。これを enforce するのは system の役目です。

Unix など、従来の OS はまず U を user account という形で model し、U と A の間の対応を、filesystem 上の ACL で表現します。それで表現できない分は、root がちまちま text file で管理します。例えば、ftp only な user は、/etc/passwd だけではなくて、ftp の共有 directory 下の設定 file で表現します。他にも /var/share/ftp 以下しか触ってはいけない ftp user がいれば、それを表現するために chroot なんていう胆試しも用意されています。

めも: 胆試しが出ない @ anthy

U が何かを起動すると、その process には U の uid が associate されます。Associate に対応する日本語が思い出せないんですね。かわいそうですね。Uid が process に割り振られるのは、その process が U の代理として活動しているからです。

ところがこの approach には二つ問題があります。

一つは、U が一度に執行する権限の集合と A はほとんどの場合一致しないということです。例えば U が

cat foo

と打ち込んだとしましょう。これによって U は、A のうち

  • foo を読む権限
  • terminal に書き込む権限
  • S 上で /bin/cat を実行する権限

の三つを執行しています。それ以外の権限は全く執行していません。しかし cat は A に含まれる全ての権限を持って走っています。もし cat に、"~/.bashrc の最後に bar という文字列を書き足せ" という trojan が仕込まれていたとすると、cat にはそれができてしまいます。あるいは cat にたまたま "foo という file 名を与えられると foo を上書きしてしまう" バグがあっても笑えない事が起きます。

もう一つは一時的に権限を与える、という操作を気軽にできないことです。U が、user V に /home/u/foo という file を弄ってほしいとします。巨大な file なので /tmp に置いてやり取りすることはできません。大体そんなん美しくないし、操作ミスの温床にもなります。しかし V と大の友達というわけでもないので /home/u/ 以下にある file 全てに access を与えるわけにはいきません。
Unix 的にはここで U, V が二人とも所属する group G を作り、chgrp G /home/u/foo するなり、setgid した program を用意するなりします。多分。知らんけど。前者の方が多いでしょうね。ところがここで G が予め用意されていなければ、管理者を叩き起こして呼びつけるなんて非人道的な行為に走るしかありません。そんなことするから人件費が上がって管理費が嵩むんですね。そうしたくなければ、初めからこういう事態を予測して、ありとあらゆる user の組合せの group を用意しておきます。user 数が n の system では、
nC2 + nC3 + nC4 + ... + nCn = 2**n - n - 1
程度の group を作ることになりますね。美しいですね。50 人ぐらいで共有してる system では /etc/group が数 EB に腫れ上がるでしょうか。組合せの計算には全く自信がありませんので正しい式を教えていただければ幸いです。しかし Exa bytes て。

Unix でももうちょっと華麗に解決できるのかもしれませんが、そもそもなぜこんな問題が起きるかと考えると、たった二つの原因につきあたります。

そもそも権限は A のような、「user の全権限」単位では使われないということが一つ。一つ目の例で示されたように、権限を執行するときは普通、持てる全権限の部分集合を取り出して使います。また、二つ目の例にあるように、自分の持っている権限のこれまた部分集合を、一時的に貸したり借りたりすることもあるということです。他にも、例えば /sbin/passwd は setuid されていて root で走りますが、/sbin/passwd が実行するのは root の持つ神の如き権限のうち「/etc/passwd が読み書きできる」という権限だけです。Filesystem をぶっ壊したり、kernel に直に code を注入したり、shutdown -h now したりする権限は要りません。

もうひとつの原因は、「個々の権限」というものが first class object として気軽に投げ回せないことです。「権限」を直に扱うのではなく、「権限に対応する user account」というものしか操作できないから、気軽に「この file の access だけね」という権限を他人に貸し与えられないわけです。

ここまで来たら後は自明です。「個々の権限」をそれぞれ kernel object にして、それを権限を扱うときの最小単位にすればいいわけです。そんな感じ。