システムコールテーブル(と呼ばれますsys_call_table
)は静的なサイズの配列であるため、これはできません。そして、そのサイズは、登録されたsyscallの数によってコンパイル時に決定されます。これは、別のスペースがないことを意味します。
が定義されているarch/x86/kernel/syscall_64.c
ファイルで、たとえばx86アーキテクチャの実装を確認できますsys_call_table
。そのサイズは正確__NR_syscall_max+1
です。__NR_syscall_max
は(最後のsyscallの数です)arch/x86/kernel/asm-offsets_64.c
として定義されsizeof(syscalls) - 1
ます。ここsyscall
で、はすべてのsyscallを含むテーブルです。
考えられる解決策の1つは、既存の(または、アーキテクチャに存在する場合は廃止されたものsys_setaltroot
など)システムコール番号を再利用することです。これにより、メモリ内により多くのスペースが必要なくなります。一部のアーキテクチャでは、syscallテーブル(64ビットバージョンのx86など)にも穴がある場合があるため、これも使用できます。
新しいsyscallを開発していて、実験中に再起動しないようにしたい場合は、この手法を使用できます。新しいシステムコールを定義し、syscallテーブルで既存のエントリを見つけて、モジュールから置き換える必要があります。
カーネルモジュールからこれを行うのは簡単ではありません。カーネルはsys_call_table
バージョン2.6の時点ではモジュールにエクスポートされないためです(このシンボルがエクスポートされた最後のカーネルバージョンはでした2.5.41
)。
これを回避する1つの方法は、sys_call_table
シンボルをモジュールにエクスポートするようにカーネルを変更することです。これを行うには、次の2行を追加する必要がありますkernel/kallsyms.c
(本番マシンではこれを行わないでください)。
extern void *sys_call_table;
EXPORT_SYMBOL(sys_call_table);
別の手法は、syscallテーブルを動的に見つけることです。カーネルメモリを反復処理し、各単語を既知のシステムコール関数へのポインターと比較します。テーブル内のこの既知のsyscallのオフセットがわかっているので、テーブルの開始アドレスを計算できます。