mod_selinux 再び

Apache/httpdから起動される web application インスタンスに個別のセキュリティコンテキストを付与するため、ここ1年くらい、色々なアイデアを試している。

前のアイデアでは、httpdの標準MPM(Multi Processing Module)である prefork から派生した実装で、各リクエストを受け付けるたびに one time thread を作成し、それにセキュリティコンテキストを付与するようにしていた。

ただ、これだと httpd-2.2.x 系では、httpd本体のリプレースが必要になる(httpd-2.4.x系では Loadable MPMが可能になる見込み)。加えて、MPMのコードの大半は prefork のコピーなので、メンテナンスがちょっとめんどう。

なんとかFedora/RHEL標準のhttpdにloadableなモジュールとして実装できないかと、ソースコードを調査していたところ、以下のような形で実装できそうだというアイデアが閃いた。

static __thread int is_worker = 0;

static void *
selinux_worker(void *dummy)
{
    conn_rec *c = dummy;

    is_worker = 1;
    ap_run_process_connection(c);
}

static int
selinux_process_connection(conn_rec *c)
{
    apr_thread_t *thread;

    if (is_worker)
        return DECLINED;

    /* create worker thread */
    rv = apr_thread_create(&thread, NULL,
                       selinux_worker, c, c->pool);
    /* join worker thread */
    rv = apr_thread_join(NULL, thread);

    return OK;
}

One-time-threadを作っても、再び process_connection フックを呼び出したら、孫スレッドを作る羽目にならないかと思ったが、TLS(Thread Local Storage)を使ってフラグ変数を定義し、One-time-threadのコンテキストで呼び出された場合には処理をスキップする事で、従来の httpd-selinux の機能をモジュールのみで提供する事が可能になった。



当該モジュールは以下のURLにて公開している。もちろん、use it with own risk でお願いします。



インストール

[root@masu ~]# rpm -Uvh mod_selinux-2.2.1817-1.fc11.i586.rpm 
Preparing...                ################################# [100%]
   1:mod_selinux            ################################# [100%]

設定(/etc/httpd/conf.d/mod_selinux.conf)

LoadModule selinux_module modules/mod_selinux.so

# Example for authentication based configuration:
#
<Directory "/var/www/html">
# #
# # HTTP Basic Authentication
# #
AuthType       Basic
AuthName       "Secret Zone"
AuthUserFile   /var/www/htpasswd
Require        valid-user
#
# #
# # SELinux context mapping
# #
selinuxMappingFile      /var/www/mod_selinux.map
selinuxDefaultContext   *:s0
#

設定(/var/www/mod_selinux.map)

#
# Apache/SELinux plud configuration
#
# SELinux context mapping with http identifications
# =================================================

# (Format)
#            :
#      :
#
# (Example)
# foo                   httpd_php_t:s0:c0
# bar                   httpd_php_t:s0:c1
# baz                   httpd_php_t:s0:c2
#
# 127.0.0.1/8           *:s0:c0.c15
# 192.168.1.0/24        *:s0
#
# (Note)
# -  has to be bounded by httpd_t
# - '*' means this part is unchanged
# - The configuration directives of
#   selinuxDefaultDomain enables us to specify
#   the default domain/range, if no matched one.
#

alice                   *:s0:c0
bob                     *:s0:c1
eve                     *:s0:c2

これで、http認証ユーザ alice, bob, eve の3名と、その人が動かす web application の間にマッピングを行う事が可能になる。



ログファイル(/var/log/httpd/error_log)を見ると、http認証ユーザ bob に対してセキュリティコンテキストを設定した旨が出力されている。

[Sun Apr 19 11:17:57 2009] [debug] mod_selinux.c(258): [client 192.168.1.2] set security context: unconfined_u:system_r:httpd_t:s0 -> unconfined_u:system_r:httpd_t:s0:c1 (uri=/inde
x.php dir=/var/www/html/ user=bob remote=192.168.1.2)

まだ、一通り proof-of-concept のバージョンが動いてるだけなので、引き続き動作検証は行っていかねばならんのと、他には、標準のセキュリティポリシーを用意する事、Fedoraへのパッケージのプッシュが必要になるだろう。