Linux 4.11から入った参照カウンタのAPIめも

security things in Linux v4.11を読んでて参照カウンタ用のAPIが4.11に入ったとのことなので軽くめもです。

利用にはinclude/refcount.hをインクルードします。実装はlib/refcount.cです。

機能的には変数は実態はatomic_t型のrefcount_tという型が作られてます。そして、値の増減時にオーバフローとアンダフローのチェックが行われます。基本的な使い方はatomic_tと同じ感じです。わりと大きな違いとしては、atomic_t型のatomic_inc()は更新前の値が0の場合実行後は1になりますが(期待通りですね)、refcount_inc()は更新前の値が0だと更新は行わず、WARN_ON_ONCEによる警告メッセージが出ます。参照カウンタのカウンタ変数はatomic_tと同じくでunsigned int型です。

atomic_inc()は純粋にinc命令を実行してますね。

static __always_inline void atomic_inc(atomic_t *v)
{
    asm volatile(LOCK_PREFIX "incl %0"
             : "+m" (v->counter));
}

refcount_inc()の場合は、refcount_add_not_zero()が呼ばれます。この関数がfalseを返すと警告がでます。

void refcount_add(unsigned int i, refcount_t *r)
{
    WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n");

refcount_add_not_zero()は更新前の値が0だったらfalseを返します。このようなチェックはrefcount_inc()だけではなくて他の関数でも行われています。例えば、デクリメントするときに元の値が0かチェックしたり。

refcount_t型の変数の初期化は静的に行う場合はREFCOUNT_INITマクロで、動的に行うならrefcount_set()で行います。

こんな感じで使えます。

gist.github.com

実行結果

masami@saga:~/codes/refcounter_test$ dmesg
[156191.116677] refcounter_test: refcounter_test_init start
[156191.116686] refcounter_test: refcounter_test_run: cpu 2
[156191.116689] refcounter_test: refcounter_test_run: cpu 6
[156191.116692] refcounter_test: refcounter_test_run: cpu 3
[156191.116694] refcounter_test: refcounter_test_run: cpu 0
[156191.116697] refcounter_test: refcounter_test_run: cpu 4
[156191.116699] refcounter_test: refcounter_test_run: cpu 5
[156191.116701] refcounter_test: refcounter_test_run: cpu 11
[156191.116703] refcounter_test: refcounter_test_run: cpu 7
[156191.116705] refcounter_test: refcounter_test_run: cpu 8
[156191.116707] refcounter_test: refcounter_test_run: cpu 9
[156191.116709] refcounter_test: refcounter_test_run: cpu 10
[156191.116713] refcounter_test: refcounter_test_run: cpu 1
[156191.116715] refcounter_test: counter1: 13
[156191.116715] refcounter_test: counter2: 13
[156191.116716] refcounter_test: non_atomic_counter: 12
[156196.491170] refcounter_test: refcounter_test_cleanup bye

( ´ー`)フゥー...