Dale Hagglundはその通りだ。
あなたはリスクが高い場所について間違った考えを持っています。リスクが高いのは、ソケットを開いてポートにバインドし、listen()
を呼び出すという単純な行為ではなく、_ネットワークから読み込んで、読み込んだものに基づいて行動することにあります。リスクが高いのは、実際の通信を行うサービスの部分です。開く部分、bind()
、listen()
、accepts()
、さらには(ある程度)accept()
を呼び出す部分はリスクが高くなく、スーパーユーザの庇護の下で実行することができます。彼らはネットワーク上で信頼できない他人の管理下にあるデータを(inetd
の場合はソースIPアドレスを除いて)使用して行動することはありません。
これには様々な方法がある。
inetd
Dale Hagglundが言うように、古い「ネットワークスーパーサーバ」inetd.conf
がこれを行っている。サービスプロセスが実行されているアカウントは、exec()
のカラムの1つです。これは、リスニング部分と特権のドロップ部分を2つの別のプログラムに分離しているわけではなく、小さくて簡単に聴取できるが、メインのサービスコードを別のプログラムに分離し、ソケット用のオープンファイルの記述子を使って生成するサービスプロセスの中のinetd
にしている。
監査の難しさは、1つのプログラムを監査するだけなので、それほど問題ではありません。tcpserver
の大きな問題は、監査というよりも、最近のツールと比較して、シンプルで細かいランタイムサービス制御を提供していないことです。
UCSPI-TCP と daemontools
Daniel J. Bernstein 氏の UCSPI-TCP と daemontools のパッケージは、これを併用するように設計されています。代わりに、Bruce Guenter氏のほぼ同等のツールセットである daemontools-encore を使用することもできます。
ソケットファイルディスクリプタを開き、特権ローカルポートにバインドするプログラムは、UCSPI-TCP の listen()
である。accept()
とtcpserver
の両方を行います。
setuidgid
はその後、ルート権限を削除するサービスプログラムを生成するか(サービスを提供するプロトコルには、例えば、スーパーユーザとして起動してから「ログオン」することが含まれているため)、ルート権限を削除するサービスプログラムを生成します。これは、権限を削除してから適切なサービスプログラムにロードをチェーンするだけの、自己完結型の小さくて簡単に監査可能なプログラムです( qmail-smtpd
のように、スーパーユーザ権限で実行されることはありません)。
サービスrun
スクリプトは以下のようになります(これはnull IDENTサービスを提供するための dummyidentd 用のものです):
#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl
nosh
私のnoshパッケージ はこれを行うために設計されています。他のものと同じように、小さな setuidgid
ユーティリティを持っています。1つのわずかな違いは、UCSPI-TCPサービスと同様にsystemd
スタイルの “LISTEN_FDS "サービスでも使用できるということで、従来のtcpserver
プログラムは2つの別々のプログラムに置き換えられます。tcp-socket-listen
と tcp-socket-accept
です。
ここでも、単一目的のユーティリティがスポーンされ、互いにチェーンロードされます。この設計の興味深い奇抜さの一つは、listen()
の後ではなく、accept()
よりも前にスーパーユーザ権限を削除できるということです。以下に run
用の qmail-smtpd
スクリプトを示します。
#!/bin/nosh
fdmove -c 2 1
clearenv --keep-path --keep-locale
envdir env/
softlimit -m 70000000
tcp-socket-listen --combine4and6 --backlog 2 ::0 smtp
setuidgid qmaild
sh -c 'exec \
tcp-socket-accept -v -l "${LOCAL:-0}" -c "${MAXSMTPD:-1}" \
ucspi-socket-rules-check \
qmail-smtpd \
'
スーパーユーザの庇護の下で実行されるプログラムは、小さなサービスに依存しないチェインローディングツール fdmove
, clearenv
, envdir
, softlimit
, tcp-socket-listen
, setuidgid
, sh
, smtp
, および daemontools
である。run
が起動された時点で、ソケットはオープンでs6-tcpserver
ポートにバインドされており、プロセスはスーパーユーザ権限を持たなくなります。
s6, s6-networking, and execline
Laurent Bercot の s6 と s6-networking パッケージは、このようなことを同時に行うように設計されています。これらのコマンドは、構造的にはtcpserver
とUCSPI-TCPと非常によく似ています。
s6-setuidgid
のスクリプトは、 setuidgid
を chpst
に、 tcpsvd
を fnord
に置き換えた以外はほとんど同じである。しかし、M. Bercotの execline ツールセットを同時に利用することもできます。
以下は Wayne Marshall’s original を軽く修正したFTPサービスの例で、execline、s6、s6-networking、および publicfile のFTPサーバプログラムを使用しています。
#!/command/execlineb -PW
multisubstitute {
define CONLIMIT 41
define FTP_ARCHIVE "/var/public/ftp"
}
fdmove -c 2 1
s6-envuidgid pubftp
s6-softlimit -o25 -d250000
s6-tcpserver -vDRH -l0 -b50 -c ${CONLIMIT} -B '220 Features: a p .' 0 21
ftpd ${FTP_ARCHIVE}
ipsvd
Gerrit Papeの[ipsvd は、ucspi-tcpとs6-networkingと同じラインで動作する別のツールセットです。今回のツールはrun
とsystemd
ですが、やっていることは同じで、ネットワーク経由で送られてきたものの読み取り、処理、書き込みを 信頼されていないクライアントはまだ別のプログラムの中にあります。
ここに、systemd
スクリプトで inetd
を実行した M. Pape の例 があります。
#!/bin/sh
exec 2>&1
cd /public/10.0.5.4
exec \
chpst -m300000 -Uwwwuser \
tcpsvd -v 10.0.5.4 443 sslio -v -unobody -//etc/fnord/jail -C./cert.pem \
fnord
systemd
systemd
は、いくつかのLinuxディストリビューションで見られる新しいサービス監視およびinitシステムで、 systemd
ができることを目的としているです。しかし、小さな自己完結型のプログラム群を使用しているわけではありません。残念ながら、systemd
全体を監査しなければならない。
systemd
では、listen()
がリッスンするソケットと、accept()
が起動するサービスを定義するための設定ファイルを作成する。サービスの「ユニット」ファイルには設定があり、どのユーザで実行するかなど、サービスプロセスを大幅に制御できるようになっている。
そのユーザを非スーパーユーザに設定すると、0x6&はソケットを開き、ポートにバインドし、プロセス#1の0x6&(および必要に応じて0x6&)をスーパーユーザとして呼び出し、生成されたサービスプロセスはスーパーユーザ権限なしで実行される。