ロード可能なカーネルモジュール(LKM)は、オペレーティングシステムの実行中のカーネル(いわゆるベースカーネル)の機能を拡張する実行可能ライブラリです。LKMは通常、新しいハードウェア(デバイスドライバなど)やファイルシステムのサポートを追加したり、システムコールを追加したりするために使用されます。LKMが提供する機能が不要になった場合は、メモリやその他のリソースを解放するためにアンロードできます。
現在主流のUnix系システムやWindowsは、ロード可能なカーネルモジュールをサポートしていますが、FreeBSDではカーネルロード可能モジュール(kld) 、macOSではカーネル拡張機能(kext)(ただし、サードパーティ製モジュールのサポートは廃止されつつあります[ 1 ] ) [ 2 ]、AIXではカーネル拡張モジュール、HP-UXでは動的ロード可能カーネルモジュール[ 3 ]、Windows NTではカーネルモードドライバ[ 4 ] 、 VxWorksではダウンロード可能カーネルモジュール(DKM) など、名称が異なります。これらはカーネルロード可能モジュール(KLM)または単にカーネルモジュール(KMOD)とも呼ばれます。
ロード可能なカーネルモジュールがない場合、オペレーティングシステムは想定されるすべての機能をベースカーネルに直接コンパイルして組み込む必要がある。そうした機能の多くはメモリ上に保持されるものの使用されないため、メモリの無駄遣いとなり、ユーザーは新しい機能が必要になるたびにベースカーネルを再構築して再起動しなければならない。
モジュール型カーネルを静的カーネルよりも優先することに対する些細な批判の一つに、いわゆるフラグメンテーション・ペナルティがあります。ベースカーネルは、セットアップルーチンによって常に実際の連続メモリに展開されるため、ベースカーネルコードが断片化されることはありません。システムがモジュールを挿入できる状態になると(例えば、モジュールを含むファイルシステムがマウントされると)、新しいカーネルコードが挿入されるとカーネルが断片化され、 TLBエントリの使用が増加し、TLBミスが増えることで、わずかなパフォーマンス低下が生じる可能性があります。
Linux のロード可能なカーネル モジュールは、modprobeコマンドによってロード (およびアンロード) されます。これらは/lib/modules、またはにあり/usr/lib/modules、バージョン 2.6 以降は拡張子.ko("カーネル オブジェクト") が付いています (以前のバージョンでは拡張子が使用されていました.o)。[ 5 ]コマンドlsmodは、ロードされたカーネル モジュールを一覧表示します。システムがモジュールの破損などにより起動に失敗した緊急時には、カーネル ブート パラメータ リストを変更することによって、特定のモジュールを有効または無効にすることができます (たとえば、GRUB を使用している場合は、GRUB スタート メニューで 'e' を押してから、カーネル パラメータ行を編集します)。
Linuxのメンテナーの見解では、LKMはカーネルから派生した作品である。Linuxのメンテナーは、 NVIDIA GPUドライバなどのプロプライエタリモジュールの配布を容認しているが、メインラインLinuxカーネルのカーネルツリーにマージできるのはGNU General Public License(GPL)モジュールのみである。
独自仕様またはGPL互換でないモジュールをロードすると、実行中のカーネルに「汚染」フラグ[ 6 ] [ 7 ]が設定され、発生した問題やバグがメンテナーによって調査される可能性が低くなります。 [ 8 ] [ 9 ] LKMは事実上実行中のカーネルの一部となるため、カーネルのデータ構造を破損させ、モジュールが実際に独自仕様である場合は調査できないバグが発生する可能性があります。
2004年、独自のデバイスドライバをロード可能なカーネルモジュールとしてリリースするコンサルティング会社であるLinuxantは、以下のコード抜粋に示すように、自社のファイル内のヌル終端文字を悪用しようと試みました。MODULE_LICENSE
MODULE_LICENSE ( " GPLディレクトリ内のファイルにはGPL \0が適用されます。その他のファイルにはLICENSEファイルのみが適用されます" );当時カーネルで使用されていた文字列比較コードは、モジュールがGPLライセンスであるかどうかを判定しようとしましたが、ヌル文字(\0)に到達すると停止したため、モジュールがライセンスを単に「GPL」と宣言していると誤解してしまいました。[ 10 ]
FreeBSDのカーネル モジュールは、オペレーティングシステム/boot/kernel/に付属するモジュールの場合は 、FreeBSD ポートまたはFreeBSD パッケージからインストールされたモジュールの場合は通常、プロプライエタリ モジュールまたはバイナリのみのモジュールの場合は に格納されます。FreeBSD カーネル モジュールは通常 拡張子を持ちます。マシンが起動したら、コマンドでロードし、コマンドでアンロードし、コマンドで一覧表示できます。モジュールは、カーネルが起動する前に、自動的に ( を介して) または手動でローダーからロードすることもできます。/boot/modules/.kokldloadkldunloadkldstat/boot/loader.conf
macOS の一部のロード可能なカーネルモジュールは自動的にロードできます。ロード可能なカーネルモジュールは、kextloadコマンドでもロードできます。また、コマンドで一覧表示することもできます。ロード可能なカーネルモジュールは、拡張子 のバンドルkextstatに格納されています。オペレーティングシステムに付属のモジュールはディレクトリに格納され、サードパーティが提供するモジュールは他のさまざまなディレクトリに格納されています。.kext/System/Library/Extensions
NetWareカーネルモジュールは、 NetWareロード可能モジュール(NLM)と呼ばれます。NLMはLOADコマンドによってNetWareカーネルに挿入され、UNLOADコマンドによって削除されます。このmodulesコマンドは現在ロードされているカーネルモジュールの一覧を表示します。NLMはNetWareサーバーに割り当てられた有効な検索パスであればどこにでも配置でき、.NLMファイル名拡張子は.NETです。
ダウンロード可能なカーネルモジュール(DKM)タイプのプロジェクトを作成すると、「.out」ファイルが生成され、これを「ld」コマンドを使用してカーネル空間にロードできます。このダウンロード可能なカーネルモジュールは、「unld」コマンドを使用してアンロードできます。
Solaris には、カーネル モジュールのロード パスを設定可能で、デフォルトは です/platform/platform-name/kernel /kernel /usr/kernel。ほとんどのカーネル モジュールは の下のサブ ディレクトリにあります/kernel。システムを init が起動できる状態まで起動するために必要とみなされないモジュールは、多くの場合 (常にではありませんが) にあります/usr/kernel。DEBUG カーネル ビルドを実行すると、システムは積極的にモジュールのアンロードを試みます。
Linuxはカーネルモジュールに対して安定したAPIやABIを提供していません。そのため、カーネルのバージョンによって内部構造や機能に違いが生じ、互換性の問題が発生する可能性があります。こうした問題に対処するため、ロード可能なELF.modinfoモジュールのセクション内にシンボルバージョン情報が格納されます。このバージョン情報は、モジュールをロードする前に実行中のカーネルのバージョン情報と比較されます。バージョンに互換性がない場合は、モジュールはロードされません。
Solaris、FreeBSD、macOS、Windowsなどの他のオペレーティングシステムは、カーネルAPIとABIを比較的安定させているため、この問題は発生しません。例えば、カーネルバージョン6.0向けにコンパイルされたFreeBSDカーネルモジュールは、6.4などの他のFreeBSD 6.xバージョンでは再コンパイルなしで動作します。ただし、他のメジャーバージョンとは互換性がなく、FreeBSD 7.xで使用するには再コンパイルが必要です。これは、APIとABIの互換性がブランチ内でのみ維持されるためです。
ロード可能なカーネルモジュールは実行中のカーネルを変更する便利な方法ですが、侵害されたシステム上の攻撃者がこれを悪用して、プロセスやファイルの検出を回避し、システムに対する制御を維持する可能性があります。多くのルートキットはこのようにLKMを利用しています。ほとんどのオペレーティングシステムでは、 LKMをロードするには特権昇格が必要なため、モジュールは特権昇格には何ら役立たず、単に攻撃者が侵入を隠蔽しやすくするだけです。[ 11 ]
Linux では、sysctlオプションを使用してモジュールのロードを無効にすることができます/proc/sys/kernel/modules_disabled。[ 12 ] [ 13 ] initramfsシステムは、起動時にマシンに必要な特定のモジュールをロードし、その後モジュールのロードを無効にすることができます。これにより、セキュリティはモノリシック カーネルと非常によく似たものになります。攻撃者が initramfs を変更できる場合、カーネル バイナリも変更できます。
OS X Yosemite以降のリリースでは、カーネル拡張機能は、特定の「権限」を持つ開発者証明書でコード署名する必要があります。このような開発者証明書は、Apple が要求に応じてのみ提供し、 Apple Developerメンバーに自動的に付与されるわけではありません。この機能は「kext 署名」と呼ばれ、デフォルトで有効になっており、署名されていないカーネル拡張機能が存在する場合はカーネルの起動を停止するように指示します。[ 14 ] OS X El Capitan以降のリリースでは、システム整合性保護の一部となっています。
古いバージョンの macOS では、または kext 署名が無効になっている場合、カーネル拡張バンドルのプロパティ リストで OSBundleAllowUserLoad プロパティが True に設定されていれば、非ルート ユーザーでもカーネル拡張バンドル内のロード可能なカーネル モジュールをロードできます。[ 15 ]ただし、実行可能コード ファイルを含むバンドル内のいずれかのファイルが、root および wheel グループによって所有されていないか、グループまたは「other」によって書き込み可能になっている場合、カーネル ロード可能なモジュールをロードしようとすると失敗します。[ 16 ]
カーネルモジュールには、オプションで暗号署名ELFセクションを含めることができ、これは検証ブートポリシーの設定に応じてロード時に検証されます。カーネルは、モジュールが信頼できる証明書セットによって暗号署名されていることを強制できます。信頼できる証明書のリストは、一部のSPARCベースのプラットフォームでは、OSの外部にあるILOMに保持されます。ユーザー空間からカーネルモジュールをロードできるのは、システムが不変グローバルゾーン機能を有効にして実行されている場合に限り、信頼できるパスからのみです。
{{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)