param_set_charp()から呼び出している maybe_kfree_parameter() と kmalloc_parameter() の中でリスト操作をしています。リスト操作は list_add(), list_del(), list_for_each_entry() です。これらは基本的な双方向リンク・チェインの操作です。ユーザー・ランドから write() system call は平行して使うことができます。何処かで排他制御をして、リンク・リスト操作を一貫して行う必要が有ります。排他制御がされているのか追ってみましょう。
dump_stack() を使って追跡することにします。param_set_charp() が呼ばれるまでの Call 経路は構造体に格納された関数を指すポインタを使って決まっています。追跡難度か高いです。kernel/params.c を次のように修正します(修正済みファイル)。Kernel を make、インストールして様子を探ることにします。
1 2 3 4 5 6 7 8 9 10 11 | ! | |
|
dump_stack()を通過する頻度に注意
ここでは dump_stack() を無条件に呼ぶように実装しました。通過頻度が少ないと見込んだためです。高頻度に通過する場合、過剰なログ出力で Linux が起動しなかったり、起動したとして応答が悪くコマンド投入が困難な状況になります。予め高頻度に通過する場所だと予想されるならば、dump_stack() を条件付きで呼び出すように修正してください。
module_param を実装した hello_world モジュールを使い call trace を得ます。
[ 212.911142] hello_world: module verification failed: signature and/or required key missing - tainting kernel [ 212.913390] hello_world_init: Hello Taro san. return_value=0 [ 241.250795] CPU: 0 PID: 2252 Comm: bash Tainted: G OE 4.1.27-local+ #3 [ 241.250819] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 241.250834] 0000000000000000 ffff88007bac3d58 ffffffff817d0d29 ffffffffc025a0d8 [ 241.250852] ffff88007b781988 ffff88007bac3d88 ffffffff8109943b ffff88007bac3d88 [ 241.250867] ffff88005cd62ea8 0000000000000006 ffff88007b781988 ffff88007bac3db8 [ 241.250881] Call Trace: [ 241.250915] [<ffffffff817d0d29>] dump_stack+0x63/0x81 [ 241.250939] [<ffffffff8109943b>] param_set_charp+0xdb/0xf0 [ 241.250957] [<ffffffff8109988d>] param_attr_store+0x4d/0xb0 [ 241.251015] [<ffffffff81275072>] ? kernfs_fop_write+0xf2/0x180 [ 241.251033] [<ffffffff81098cad>] module_attr_store+0x1d/0x30 [ 241.251047] [<ffffffff81275bfd>] sysfs_kf_write+0x3d/0x50 [ 241.251063] [<ffffffff812750aa>] kernfs_fop_write+0x12a/0x180 [ 241.251082] [<ffffffff811fa198>] __vfs_write+0x28/0xf0 [ 241.251099] [<ffffffff811fcda9>] ? __sb_start_write+0x49/0xf0 [ 241.251118] [<ffffffff81320373>] ? security_file_permission+0x23/0xa0 [ 241.251133] [<ffffffff811fa889>] vfs_write+0xa9/0x1b0 [ 241.251148] [<ffffffff811fb656>] SyS_write+0x46/0xb0 [ 241.251166] [<ffffffff81068080>] ? do_page_fault+0x30/0x80 [ 241.251227] [<ffffffff817d8b72>] system_call_fastpath+0x16/0x75
vfs_write() が Linux Kernel の仮想ファイルシステム(VFS) レイヤです。vfs_write() の中では write() システムコールを平行して扱えます。呼ばれた順に関数を並べると __vfs_write(), kernfs_fop_write(), sysfs_kf_write(), module_attr_store(), param_attr_store(), param_set_charp() となります。 これらの中から効果がある排他制御を探します。