suexec 関係
引数
常に 3 個取る。
- 引数 1: uid (番号でも名前でもよい), mod_userdir 経由のアクセスの場合は先頭に ~ が付く (e.g. ~1000)
~ が付いたままでは uid として使えないので、その場合は内部で ~ を取り除いてから使っている。(そして内部の userdir フラグを立てる) - 引数 2: gid (番号でも名前でもよい)
- 引数 3: スクリプトファイル名 (パスは含まない)
/ で始まっている場合 (絶対パスでの指定), ../ や /../ が含まれている場合 (上位ディレクトリを参照しようとしている) はエラーを吐いて実行を拒否 - Action 等で Handler から呼ばれる場合、実行したいスクリプト本体は環境変数 PATH_INFO と PATH_TRANSLATED で指定される。
動作
スクリプトファイルのディレクトリに chdir された状態で実行が開始される。
- 許可済みの環境変数のみが含まれた”クリーンな”環境を生成
- 自分の uid を取得し、/etc/passwd の中に存在するかチェック
- さらに、自分の uname が AP_HTTPD_USER かどうかチェック
- 第一引数が -V かどうかチェックし、もしそうならコンパイル情報を表示して終了
- その際、uid が 0 (root) か apache の実行ユーザーかチェックし、そうでないなら表示しない
- 引数が 3 つ未満なら異常終了
- スクリプトファイル名をチェック。以下のようになっていたら異常終了
- / で始まっている (絶対パスの指定はダメ)
- ../ で始まっている (上位ディレクトリに行こうとしてるのはダメ)
- /../ を含んでいる (ダメ)
- uid の先頭に ~ が付いているかチェックし、付いていたら内部の userdir 使用フラグを立てて ~ を削除
- SUEXEC_DOCROOT と SUEXEC_USERDIR_SUFFIX を取得してチェック
- SUEXEC_USERDIR_SUFFIX は全てアルファベットか数字で構成されている必要あり、’.’ で始まらない必要あり
- SUEXEC_DOCROOT は ‘/’ で始まっていないとダメ (絶対パスのみ許可)、一文字で終わっていたり ‘/’ や ‘.’ が二文字目にあったらダメ
- 指定された実行用 uid と gid が存在するかチェック
- ログに uid, gid, スクリプト名を記録
- 指定された uid/gid が最小値以上になっているかチェック
- gid -> uid の順にプロセスが持つ現在の id から指定された id へ変更
- カレントディレクトリのパスを取得し、正当性をチェック (SUEXEC_DOCROOT の中にあるか等)
- 具体的な方法は後でもっとよく見る
- カレントディレクトリは本当にディレクトリか?(違ったら異常終了)
- カレントディレクトリは others または group から書き込み可能でないか?
- group を許可するオプション付けてくれてもいいよね…
- 実行しようとしているスクリプト本体にアクセスできるか?
- スクリプト本体は others または group から書き込み可能でないか?
- group をどうにかするオプションを…
- スクリプト本体は setuid または setgid されていないか?
- 指定された uid/gid が
- スクリプト本体の uid/gid と同じか?
- カレントディレクトリの uid/gid と同じか?
- スクリプト本体に所有者の実行権限が付いているか?
- AP_SUEXEC_UMASK で指定された umask をセット
- others および group に対して書き込み権限がセットされないかチェック
- ログファイルをクローズ
- exec() が成功した時にのみ閉じるようなフラグをセットすることで実現
- スクリプト本体を実行
- execve() でプロセス自体をスクリプト本体に移行させるので、この時点で suexec のプロセスは終わる
- 実行に失敗したらエラーを吐いて終了