libselinuxを使うかどうか(1)

PostgreSQLの中でlibselinux関数を使う場合、気をつけなければいけないのがリソースの確保/解放
PostgreSQLは独自にメモリ管理機構を持っていて、基本的にはpalloc()関数でメモリを取得する。これはMemoryContextと呼ばれるメモリ管理構造からメモリを割り当てるが、面白いことに、同一のMemoryContextから割り当てたメモリ領域は、後で一気に解放できる。そのため、リークの心配がない。
一方、libselinuxを使ってgetcon()とかした場合、内部的にmalloc()してメモリを確保するので、これらは確実にfree()しなければならない。まぁ、当然といえば当然だが、PostgreSQLの中でこれをやると実は結構めんどい。

PostgreSQLの中で何かエラーが発生すると、ereport()関数を呼び出す。こやつは、エラーメッセージを生成すると共に、long-jumpでいきなり呼び出し元に戻ってしまう。なので、以下のようなコードがあると非常にまずい。

  security_id_t tsid;
if (avc_context_to_sid(tcon, &tsid)!=0)
ereport(...., "could not obtain SID of '%s'", tcon);
if (avc_has_perm(SelinuxClientSid, tsid, .....) != 0)
ereport(...., "XXXX access denied");
なぜかというと、avc_has_perm()がエラーを返して、即座にereport()でlong-jumpによるリターンを許してしまうと、tsidのリソース確保にmalloc()したままfree()せずに戻ってしまうため。
PostgreSQLのデータ構造は、long-jumpで戻った時点で『CurrentMemoryContextから割り当てたメモリ全部解放!』の呪文で解放されるが、malloc()/free()はそうはいかない。

まぁ、地道にコードを書けばいいのだが、そう毎回エラーパスが複雑になると、いい加減嫌になってくるし、バグだって入りやすくなる。
いっそ、内部的に palloc() を使う libselinux 相当のモノを作ってやろうかと考え中・・・。