builtin_object_size
__builtin_object_sizeはgccの機能で、コンパイル時にサイズを取得します。以降私の解釈です。引数のtypeは0/1/2/3ですが、そうでなくビット0/ビット1としてのフラグとなります。typeが0/2すなわちビット0がセットされない場合と、(type=1/3)でビット0がセットされている場合。typeが0/1のビット1がセットされない場合と、(type=2/3)でビット1がセットされている場合での対応です。
ビット0がセットされていれば引数そのもののサイズ、セットされていればかかるバッファに関連する領域も含めてのサイズとなります。
ビット1がセットされていればサイズが取得できない時の返値は0、されてなければ-1となります。
__builtin_object_size()は、staticバッファを前提とした機能で、サイズチェックをコード上に記述する手間を無くします。(サイズ値の変更毎にかかる修正も必要ありません。gccが行ってくれます。)
なお、サイズが取得できない時の返値を-1/0としてる理由ですが、返値をそのままstrncpy()等の引数とするケースを想定してのことではと・・・。そうする事で最悪のケースは必ず回避できます。
ビット0がセットされていれば引数そのもののサイズ、セットされていればかかるバッファに関連する領域も含めてのサイズとなります。
ビット1がセットされていればサイズが取得できない時の返値は0、されてなければ-1となります。
#include "stdio.h" static void obj_size(void* to); struct hoge { char buf0[10]; char buf1[20]; char buf2[30]; }; void main() { obj_size("12345"); } static void obj_size(void* to) { struct hoge buf; printf("%d\n", __builtin_object_size(buf.buf1, 0)); printf("%d\n", __builtin_object_size(buf.buf1, 1)); printf("%d\n", __builtin_object_size(buf.buf1, 2)); printf("%d\n", __builtin_object_size(buf.buf1, 3)); printf("\n"); printf("%d\n", __builtin_object_size(to, 0)); printf("%d\n", __builtin_object_size(to, 1)); printf("%d\n", __builtin_object_size(to, 2)); printf("%d\n", __builtin_object_size(to, 3)); }
[root@localhost lkm]# ./a.out 50 20 50 20 -1 -1 0 0
補足
__compiletime_object_size()は、ユーザ空間からカーネル空間にバッファを複写するcopy_from_user()で使われています。__compiletime_object_size()の引数は、copy_from_user()の引数toで、それではサイズが取得できないのではと。故copy_from_user()はinlineで展開されます。__builtin_object_size()は、staticバッファを前提とした機能で、サイズチェックをコード上に記述する手間を無くします。(サイズ値の変更毎にかかる修正も必要ありません。gccが行ってくれます。)
なお、サイズが取得できない時の返値を-1/0としてる理由ですが、返値をそのままstrncpy()等の引数とするケースを想定してのことではと・・・。そうする事で最悪のケースは必ず回避できます。
#define __compiletime_object_size(obj) __builtin_object_size(obj, 0) static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { int sz = __compiletime_object_size(to); might_fault(); if (likely(sz == -1 || sz >= n)) n = _copy_from_user(to, from, n); #ifdef CONFIG_DEBUG_VM else WARN(1, "Buffer overflow detected!\n"); #endif return n; }sz==-1の時も、_copy_from_user()となっていますが、呼び出し側で動的にバッファを確保するケースで、複写するサイズ分のバッファを確保したり、ないし呼び出し側で複写サイズとバッファに応じたチェックを行うことを前提とします。