セキュリティコンテキストの格納

今更ながら、セキュリティコンテキストの格納方法を変更した。

理由は、ビルド時にSE-PostgreSQLを無効化する場合と有効化した場合のどちらも正しく動作するようパッチを作ると、パッチ適用が必要な箇所が多くなり、いずれメンテナンスに必要な労力が多くなってしまうだろうから。

今までは、テーブルを作成する際に勝手に'security_context'というカラムを追加して、タプル毎のセキュリティコンテキストをそのカラムに格納するようにしていた。
テーブルやカラムのセキュリティコンテキストは、これらのDBオブジェクトの内部表現である pg_class/pg_attribute システムカタログ(特殊なテーブル)にセキュリティコンテキスト格納用のフィールドを用意して格納している。
つまり、テーブルに含まれるどこかのカラムがセキュリティコンテキストを格納していたわけだ。

しかし、この方法だとシステムカタログの形を変更するというかなり根本的な修正なので、SE-PostgreSQLのdisable/enable時に相当大きなブロックに対しパッチ適用が必要になる。

一方、今回用いた方法は、各タプルの内部表現である HeapTupleHeader 構造体に、セキュリティコンテキストを表現する t_security というメンバを持たせて 'security_context' システム列からアクセス可能にするという方法。
こちらの方法だと、システムカタログの形を修正しなくて済むので、パッチの行数が少なくて済む。即ち、本流への追従が比較的楽。

実は、元々の方法の方が実装は楽である。
なぜなら、'security_context'列は普通のデータ列と変わらないので、何も変更せずにINSERT/UPDATEが可能だった。一方、PostgreSQLのシステム行(tableoidなど)というのはread-onlyが仮定されており、UPDATEやINSERTの対象にできないという問題がある。

ここで私はどうやって折り合いを付けたか。

'security_context'へのUPDATE/INSERTなどがあると、その箇所を勝手にジャンク列へのUPDATE/INSERTとしてしまう。ジャンク列にすると、タプルに挿入すべき値が計算されるが、その計算結果はUPDATE/INSERT処理の直前にフィルタリングされ、実際の結果には反映されない。(なぜこういった機構があるかというと、ORDER BY等に必要な値を計算する場合があるので。)

で、そのフィルタリング直前にジャンク列として計算された'security_context'の値を取り出し、それを HeapTupleHeader の t_security メンバに書き出してやれば、explicit labelingの完成というわけだ。

コードの行数なら200L程度の仕掛けだが、これを使うことでシステム列へのUPDATE/INSERTを実装できた。この感動を誰かと分かち合いたい。(←マニアックすぎだよ)