LIDS Part4

面 和毅

LIDS Part4



ACL の継承

前回までで、システムでは基本的な設定ができている(/root, /var などがREADONLY になっている)状態になっているはずです。 lidsconf -l の出力結果は
Using ACL FILE: /etc/lids/lids.conf
LIST
	 effective capability = 0x00000000

                Subject   ACCESS  inherit time        Object
----------------------------------------------------------------------------
               Any file  READONLY:  0  0000-0000                 /sbin 0
               Any file  READONLY:  0  0000-0000                  /bin 0
               Any file  READONLY:  0  0000-0000                 /boot 0
               Any file  READONLY:  0  0000-0000                  /lib 0
               Any file  READONLY:  0  0000-0000                  /usr 0
               Any file  READONLY:  0  0000-0000                  /var 0
               Any file  READONLY:  0  0000-0000                  /tmp 0
               Any file  READONLY:  0  0000-0000                  /etc 0
               Any file      DENY:  0  0000-0000             /etc/lids 0
               Any file      DENY:  0  0000-0000           /etc/shadow 0
               Any file    APPEND:  0  0000-0000              /var/log 0
               Any file     WRITE:  0  0000-0000         /var/log/wtmp 0
             /bin/login  READONLY:  0  0000-0000           /etc/shadow 0
                /bin/su  READONLY:  0  0000-0000           /etc/shadow 0
               Any file  READONLY:  0  0000-0000        /usr/local/etc 0
                /bin/su     GRANT:  0  0000-0000            CAP_SETUID 0
                /bin/su     GRANT:  0  0000-0000            CAP_SETGID 0
               Any file  READONLY:  0  0000-0000                 /root 0
               Any file  READONLY:  0  0000-0000   /root/.bash_history 0
             /bin/login     WRITE:  0  0000-0000         /var/log/wtmp 0
             /bin/login     WRITE:  0  0000-0000      /var/log/lastlog 0
             /sbin/init     GRANT:  0  0000-0000              CAP_KILL 0
  /etc/rc.d/init.d/halt     GRANT:  1  0000-0000              CAP_KILL 0
  /etc/rc.d/init.d/halt     GRANT:  1  0000-0000         CAP_NET_ADMIN 0
  /etc/rc.d/init.d/halt     GRANT:  1  0000-0000         CAP_SYS_ADMIN 0
               Any file  READONLY:  0  0000-0000            /home/omok 0
              /bin/bash    APPEND:  0  0000-0000  /home/omok/.bash_history 0
となっています。この状態で、次の簡単なテストスクリプトを走らせます。

----------------------------/tmp/testwrite.sh------------------------
#!/bin/sh

cp /tmp/tmpfile /var/tmp
----------------------------------------------------------------------


/var をREADONLY にしてあるので、/var/tmp も当然READONLY になっています。 そこで、このスクリプトを実行して、/var/tmp に書き込みを行えるように権限 を与えます。
# lidsadm -S -- -LIDS_GLOBAL 
で、LFS に移動し
lfs# lidsconf -A -s /tmp/tempwrite.sh -o /var/tmp -j WRITE
とします。
lfs# lidsconf -L
とすると、一番最後の行(最後に加えたACL が最下段に表示されます)に
      /tmp/testwrite.sh    WRITE:  0  0000-0000  /var/tmp 0
が追加されます。

これで/tmp/testwrite.sh が正常に走るのでしょうか? 実行してみましょう。

lfs# lidsadm -S -- +LIDS_GLOBAL
# /tmp/testwrite.sh
cp: cannot create regular file `/var/tmp/tmpfile': Operation not permitted

というエラーが出て来ます。/var/log/messages を見てみると
Jan 28 01:00:28 nemesis kernel: LIDS: cp (dev 3:68 inode 289112) pid 1301 ppid 1300 uid/gid (0/0) on (pts) : Attempt to open /var/tmp/tmpfile for writing,flag=32834 
このログから、/tmp/testwrite.sh のシェルスクリプト内にあるcp コマンドが呼び出された時に、 /var/tmp/tmpfile という宛先にファイルを書き込みすることができない(書き込みの許可が与えられていない)ことが分かります。 つまり、元のプログラム(Subject)に対してACL を与えても、そのプログラムから呼び出される子プロセスに対しては、今の場合ACL が適用されないということになります。 これを解決させるためには、どうすれば良いでしょうか? /bin/cp にも/var/tmp にたいして書き込み権限を与えると言うのが、ひとつの方法です。 しかし、それですと、不適切なプログラムから/bin/cp が呼び出された時にも、 /var/tmp に書き込みを行ってしまいます。 この問題を解決するために、LIDS ではACL の継承という概念が導入されています。

LIDS でセットアップしたACL は、親プロセスがプログラム中で子プロセスを生成した時に、

  1. 親プロセスと子プロセスが同じプログラムの場合には、完全に同じACL をコピー(継承)する
  2. 親プロセスと子プロセスが異なるプログラムの場合には、子プロセスに親のACL を継承させるかどうか設定できる
のようにする事ができます。

ACL 継承のテスト

先程のACL を一旦削除して、
lfs# lidsconf -D -s /tmp/tempwrite.sh -o /var/tmp 
代わりに
lfs# lidsconf -A -s /tmp/tempwrite.sh -o /var/tmp -i 1 -j WRITE
とします。-i は「inherit(継承)」を表し、上の例では「継承レベル 1 」を示します。「継承レベル」とは、何世代目までのプロセスがACL を継承できるかを表すものです。「継承レベル 1 」では、子プロセス(第一世代)までがACL を継承できますが、孫プロセス(第二世代)には継承されません。 lidsconf -L の出力を見てみると
Using ACL FILE: /etc/lids/lids.conf
LIST
	 effective capability = 0x00000000

                Subject   ACCESS  inherit time        Object
----------------------------------------------------------------------------
               Any file  READONLY:  0  0000-0000                 /sbin 0
               Any file  READONLY:  0  0000-0000                  /bin 0
               Any file  READONLY:  0  0000-0000                 /boot 0
               Any file  READONLY:  0  0000-0000                  /lib 0
               Any file  READONLY:  0  0000-0000                  /usr 0
               Any file  READONLY:  0  0000-0000                  /var 0
               Any file  READONLY:  0  0000-0000                  /tmp 0
               Any file  READONLY:  0  0000-0000                  /etc 0
               Any file      DENY:  0  0000-0000             /etc/lids 0
               Any file      DENY:  0  0000-0000           /etc/shadow 0
               Any file    APPEND:  0  0000-0000              /var/log 0
               Any file     WRITE:  0  0000-0000         /var/log/wtmp 0
             /bin/login  READONLY:  0  0000-0000           /etc/shadow 0
                /bin/su  READONLY:  0  0000-0000           /etc/shadow 0
               Any file  READONLY:  0  0000-0000        /usr/local/etc 0
                /bin/su     GRANT:  0  0000-0000            CAP_SETUID 0
                /bin/su     GRANT:  0  0000-0000            CAP_SETGID 0
               Any file  READONLY:  0  0000-0000                 /root 0
               Any file  READONLY:  0  0000-0000   /root/.bash_history 0
             /bin/login     WRITE:  0  0000-0000         /var/log/wtmp 0
             /bin/login     WRITE:  0  0000-0000      /var/log/lastlog 0
             /sbin/init     GRANT:  0  0000-0000              CAP_KILL 0
  /etc/rc.d/init.d/halt     GRANT:  1  0000-0000              CAP_KILL 0
  /etc/rc.d/init.d/halt     GRANT:  1  0000-0000         CAP_NET_ADMIN 0
  /etc/rc.d/init.d/halt     GRANT:  1  0000-0000         CAP_SYS_ADMIN 0
               Any file  READONLY:  0  0000-0000            /home/omok 0
              /bin/bash    APPEND:  0  0000-0000  /home/omok/.bash_history 0
      /tmp/testwrite.sh    WRITE:   1  0000-0000  /var/tmp 0
となり、「inherit」の項目に1 が設定されています。 この状態で、設定ファイルを再読み込みしてテストします。
lfs# lidsconf -U
lfs# lidsadm -S -- +RELOAD_CONF
lfs# lidsadm -S -- +
# /tmp/testwrite.sh
#
となり、/var/tmp を見てみると
# ls /var/tmp
 tmpfile
#
tmpfile がきちんとコピーされています。

継承レベルのテスト

継承レベルのテストとして
----------------------------/tmp/test2.sh------------------------
#!/bin/sh

/tmp/tmptestwrite.sh
----------------------------------------------------------------------
として、先程のスクリプトを呼び出す、新しいスクリプトを作ります。 先程のtestwrite.sh に関するACL を削除して、
lfs# lidsconf -D -s /tmp/tempwrite.sh -o /var/tmp 
新たに
lfs# lidsconf -A -s /tmp/test2.sh -o /var/tmp -i 1 -j WRITE
とします。継承レベルを1 に設定しています。 ここで、/tmp/test2.sh を動作させると
cp: cannot create regular file `/var/tmp/tmpfile': Operation not permitted
と、/var/tmp/tmpfile に書き込む権限が無いと言うアラートが出て来ます。 これは、継承レベルを1 に設定したため、test2.sh から直接起動されるプロセス (testwrite.sh) にはACL が継承されますが、そのtestwrite.sh から起動されるcp コマンドに関しては、test2.sh から見て孫に当たりますので、ACL が継承されていないと言う事です。 したがって、このtest2.sh がきちんと動くためには
lfs# lidsconf -A -s /tmp/test2.sh -o /var/tmp -i 2 -j WRITE
として継承レベル2 (孫) にしてあげる必要があります。 継承レベルを-1 に設定すると、無制限にACL を継承していきます。システムの設定を思考錯誤している時には継承レベルを無制限にしておき、正常に動くようになった後に継承レベルを正しく設定していく方法が良いでしょう。

ACL の実際の例

SSH によるリモートログインを許可するACL 設定

遠隔地のLIDS システムのACL を思考錯誤で設定する時には、LIDS でシステムを封印した後も、SSH でリモートログインを許可する設定が必要です。 下記は、それを許可するACL です。第一回に使用したACL に付け加える形になります。 システムは、Red Hat Linux 9 を用いて作成してありますので、パスなどは適宜システムによって変更してください。
----------------------------lids.ssh.sh---------------------------
#!/bin/sh

lidsconf -A -s /usr/sbin/sshd -o CAP_CHOWN -j GRANT 
lidsconf -A -s /usr/sbin/sshd -o CAP_FOWNER -j GRANT 
lidsconf -A -s /usr/sbin/sshd -o CAP_SYS_CHROOT -j GRANT 
lidsconf -A -s /usr/sbin/sshd -o CAP_SETGID -j GRANT 
lidsconf -A -s /usr/sbin/sshd -o CAP_SETUID -j GRANT 
lidsconf -A -s /usr/sbin/sshd -o CAP_DAC_OVERRIDE -j GRANT 
lidsconf -A -s /usr/sbin/sshd -o CAP_DAC_READ_SEARCH -j GRANT 
lidsconf -A -s /usr/sbin/sshd -o CAP_SYS_TTY_CONFIG -j GRANT 
lidsconf -A -s /usr/sbin/sshd -o /etc/shadow -j READONLY
lidsconf -A -s /usr/sbin/sshd -o /var/log/lastlog -j WRITE
--------------------------------End--------------------------------


Apache 用のACL 設定

通常、Apache などのサービスはシステムを封印する前に起動しておきます。下記の例は、システムを封印した後にApache を起動する場合です。 なお、Apacheはソースからコンパイルしていて、2.0.49 を使用しています。 configure 時のオプションは
./configure --prefix=/usr/local/apache --sysconfdir=/etc/httpd
で、httpd.conf で
ログファイル : /var/log/httpd
にしてあります。
#!/bin/sh

lidsconf -A -s /root/apachectl -i 1 -o CAP_SETUID -j GRANT
lidsconf -A -s /root/apachectl -i 1 -o CAP_SETGID -j GRANT
lidsconf -A -s /root/apachectl -i 1 -o CAP_DAC_OVERRIDE -j GRANT
lidsconf -A -s /root/apachectl -i 1 -o CAP_NET_BIND_SERVICE 80,443 -j GRANT
lidsconf -A -o /usr/local/apache -j DENY
lidsconf -A -o /etc/httpd -j DENY
lidsconf -A -s /root/apachectl -i 1 -o /etc/httpd -j READONLY
lidsconf -A -s /root/apachectl -i 1 -o /usr/local/apache -j READONLY
lidsconf -A -s /root/apachectl -i 1 -o /usr/local/apache/htdocs -j READONLY
lidsconf -A -s /root/apachectl -i 1 -o /usr/local/apache/cgi-bin -j READONLY
lidsconf -A -s /root/apachectl -i 1 -o /var/log/httpd/access_log -j APPEND
lidsconf -A -s /root/apachectl -i 1 -o /var/log/httpd/error_log -j APPEND
lidsconf -A -s /root/apachectl -i 1 -o /var/log/httpd -j WRITE
lidsconf -A -s /root/apachectl -i 1 -o /usr/local/apache/bin/httpd -j READONLY
lidsconf -A -s /root/apachectl -i 1 -o /usr/local/apache/bin/envvars -j READONLY

また、このときにはhttpd から起動ができますが、apachectl からはexport している関連で起動ができません。直接httpd を起動するか、apachectl を書き換えてPATH の部分を直接記入してください。

その他

lids.conf ファイルの編集

lidsconf で設定したACL を削除する時には、
lidsconf -D -s XXX -o XXX
として、一つ一つ削除して行くか、あるいは
/etc/lids/lids.conf
を直接編集して削除してから
lidsconf -U
でアップデートしましょう。

ACL 制限の順序

lidstools-0.5.1 を使用すると、ACL の記述順序が厳しくなります。 例を見てみましょう /var をREADONLY にし、/var/tmp をHidden にしようとします。
[root@nemesis root]# lidsconf -A -o /var -j READONLY
Using ACL FILE: /etc/lids/lids.conf
ADD
         effective capability = 0x00000000

[root@nemesis root]# lidsconf -A -o /var/tmp -j DENY
Using ACL FILE: /etc/lids/lids.conf
ADD
         effective capability = 0x00000000

lidsconf: the type is less than default permssion, this rule is useless
このように、デフォルトのパーミッションよりも、新しく設定するパーミッションの方が厳しくなる(小さくなる)場合には、上述のエラーが出て設定が出来ません。 したがって、このようにACL を設定する場合には、/var/tmp をDENY に設定した後に/var をREADONLY に設定します。 または、直接lids.conf ファイルを編集する事により実現できます。上の例ですと、/var/tmp のinode 番号などが必要になりますので、
/etc/lids/lids.conf
ファイルをコピーしてから、lidsconf -Z で全削除した後に、
lidsconf -A -o /var/tmp -j DENY
としたあとに、/etc/lids/lids.conf として保存された行を、元のファイルに付け加えて
lidsconf -U
とすれば良いでしょう。

終りに

lids でACL を設定するときには、/var/log/messages を見ながら必要なACL を加えて行きます。ただし、不必要な権限も与えてしまいすぎないように気を付けましょう。

Kazuki Omo 平成16年2月15日