前回、pgsql-hackersに投稿したパッチに対して、Tom Laneから非常に多くのコメントが付いたが、ようやくその全てに対して修正を終えた。
(最も手間がかかったのは『ドキュメント添付してよ』というリクエストだったが…。)
コーディングスタイルや、コンパイル時の警告など、自明なものもあるが、かなり根本的な修正を迫られたものもあった。
一番大きかったのは、security_label型の廃止。
以前は、システム列 "security_context" に security_label型を与え、型入力ハンドラで 文字列形式 → SecurityID への変換を行っていた。
SecurityIDは、セキュリティコンテキストの内部表現で、userspace AVCのキーにも使っている。
しかし、Read-Onlyトランザクションの中で
SELECT 'user_u:user_r:user_t:s0:c99'::security_label;なんて悪戯をすると、問題が発生する事に気が付いた。何も更新操作を行うつもりがないのに、pg_securityシステムカタログに行を追加してしまう。
これを改善するため、"security_context" システム列をTEXT型で定義し、INSERTやUPDATEでタプルが追記される直前に、文字列→SecurityIDの変換を行うようにした。
だが、これは別の問題を引き起こす。
全てのセキュリティコンテキスト(の文字列表現)が SecurityID を持つ事を担保できないため、場合によっては文字列をキーとしてuserspace AVC を探索できる必要がある。
そのため、インターフェースの追加を余儀なくされた。
また、文字列というのは事前に長さが決定できないため、固定長の共有メモリセグメントにこれを配置することはできない。従って、今までは共有メモリ上に配置していた AVC を、ローカルメモリ上に確保する必要がある。
ローカルメモリにAVCを配置すると、ポリシー再ロード時の Invalidation の問題がある。SELinuxは、ポリシーの再ロードやBooleanの設定変更をアプリに通知する機能を持っているが、共有メモリにAVCを配置するのに比べ、ローカルメモリの場合は Invalidation が煩雑だ。
結局、この問題は共有メモリに version カウンタを持たせて、それを atomic_read() する事で、各インスタンスが自分の AVC の有効性を確認できるようにした。
なんと言う美しき芋づる。
他には、行レベルのアクセス制御を、WHERE/ON句の書き換えでなく、ExecScanへのフックによって実現するようにした事で、コードの複雑さが大幅に小さくなったことなど。
そんな感じで、なんとか6末には間に合いそうか〜