ModRuidTestAgain

3,4年ぐらい前に、[wiki:ModSuid2AndModRuidAndLinuxCapability modsuid2 とか modruid とか Linux ケーパビリティとか] で、mod_ruid の setuid/setgid は、プロセス単位なのか、それともスレッド単位なのか、という実験をして、スレッド単位で setuid/setgid する、という結果が得られたんですが、Linux kernel 2.4 というだいぶ古い環境での実験だったので、比較的最近の環境で実験してみた。

OS はこんな感じ。

$ uname -a
Linux h026.southpark 2.6.18-164.el5 #1 SMP Thu Sep 3 03:28:30 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/redhat-release
CentOS release 5.4 (Final)

httpd のバージョン。

$ rpm -q httpd
httpd-2.2.3-45.el5.centos.1

ps でプロセス/スレッドが見やすいように /etc/httpd/conf/httpd.conf をいじる。

<IfModule worker.c>
StartServers        1
MaxClients          1
MinSpareThreads     1
MaxSpareThreads     1
ThreadsPerChild     1
MaxRequestsPerChild  0
</IfModule>

/etc/sysconfig/httpd の以下の行を有効にして worker mpm で動かす。

HTTPD=/usr/sbin/httpd.worker

mod_ruid は処理が終わるとすぐに元のユーザに戻してしまうので、戻らないようにコメントアウト。

#!diff
diff --git a/mod_ruid.c b/mod_ruid.c
index 5294d32..deed59b 100644
--- a/mod_ruid.c
+++ b/mod_ruid.c
@@ -269,9 +269,9 @@ static int ruid_suidback (request_rec * r)
        }
        cap_free(cap);

-       setgroups(0,NULL);
-       setgid(unixd_config.group_id);
-       setuid(unixd_config.user_id);
+       //setgroups(0,NULL);
+       //setgid(unixd_config.group_id);
+       //setuid(unixd_config.user_id);

        cap=cap_get_proc();
        capval[0]=CAP_SETUID;

apxs でビルド&インストール。

$ sudo /usr/sbin/apxs -a -i -l cap -c mod_ruid.c

/etc/init.d/httpd restart して、プロセスとスレッドの UID を確認。下3つは PID が同じなので、スレッドだと判断できる。UID はすべて apache。

$ ps -eLf
UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
root     13005     1 13005  0    1 23:29 ?        00:00:00 /usr/sbin/httpd.worker
apache   13011 13005 13011  0    3 23:29 ?        00:00:00 /usr/sbin/httpd.worker
apache   13011 13005 13013  0    3 23:29 ?        00:00:00 /usr/sbin/httpd.worker
apache   13011 13005 13014  0    3 23:29 ?        00:00:00 /usr/sbin/httpd.worker

ここで httpd へアクセスし、再度 ps で確認。

UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
root     13005     1 13005  0    1 23:29 ?        00:00:00 /usr/sbin/httpd.worker
apache   13011 13005 13011  0    3 23:29 ?        00:00:00 /usr/sbin/httpd.worker
100      13011 13005 13013  0    3 23:29 ?        00:00:00 /usr/sbin/httpd.worker
apache   13011 13005 13014  0    3 23:29 ?        00:00:00 /usr/sbin/httpd.worker

スレッドのひとつだけ UID が 100 になってる。これは mod_ruid.c に以下のようにデフォルトが定義されているから。

#!c
#define SUID_DEFAULT_UID        100
#define SUID_DEFAULT_GID        100

というわけで、スレッド単位で setuid/setgid される、ということには変わりありませんでした、という結果に。