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