1

Mac OS X ネットワーク カーネル エクステンションで、動的バッファではなく静的に割り当てられたバッファがある場合、printf() や send()、ctl_enqueuedata() などの API 関数を呼び出すと、カーネル パニックが発生することに気付きました。他の多くの人と同様に。静的に割り当てられたバッファーをコードの外部から読み書きできないかのようです。

例えば:

// This is OK
static char* somevar = NULL;
somevar = OSMalloc(50, myOSMallocTag);
bzero(somevar, 50);

// This will create a kernel panic when used outside my code
static char somevar[50];
bzero(somevar, 50);

何故ですか?

編集:コードを投稿しようとしていましたが、コードが長く、機能するバージョンとパニックを引き起こすバージョンの唯一の違いは上記のとおりです。私が念頭に置いているのは、静的変数と OSMalloc で割り当てられた変数のメモリ位置の違いです。ctl_enqueuedata() 内のコードは両方にアクセスできますか?

何が起こったかは次のとおりです。

panic(cpu 0 caller 0xffffff802eeb7e95): Kernel trap at 0xffffff802ee28896, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000031, CR3: 0x000000024fbac0a7, CR4: 0x00000000001606e0
RAX: 0x000000007fffff01, RBX: 0x0000000000000000, RCX: 0x0000000000000010, RDX: 0xffffff7fb0d4d573
RSP: 0xffffff811f6fbae0, RBP: 0xffffff811f6fbbe0, RSI: 0x000000007fffffff, RDI: 0x0000000000000073
R8:  0x0000000000000000, R9:  0x0000000000000031, R10: 0x0000000000000000, R11: 0x0000000000000000
R12: 0x0000000000000000, R13: 0x0000000000000019, R14: 0xffffff811f6fbd01, R15: 0x0000000000000031
RFL: 0x0000000000010246, RIP: 0xffffff802ee28896, CS:  0x0000000000000008, SS:  0x0000000000000010
Fault CR2: 0x0000000000000031, Error code: 0x0000000000000000, Fault CPU: 0x0

Backtrace (CPU 0), Frame : Return Address
0xffffff811f6fb780 : 0xffffff802ee1d626 
0xffffff811f6fb7f0 : 0xffffff802eeb7e95 
0xffffff811f6fb9c0 : 0xffffff802eecd4dd 
0xffffff811f6fb9e0 : 0xffffff802ee28896 
0xffffff811f6fbbe0 : 0xffffff802f174a62 
0xffffff811f6fbc00 : 0xffffff7fb0d4cead 
0xffffff811f6fbd40 : 0xffffff7fb0d46101 
0xffffff811f6fbdf0 : 0xffffff802f150525 
0xffffff811f6fbe40 : 0xffffff802f1990b2 
0xffffff811f6fbef0 : 0xffffff802f1a04f2 
0xffffff811f6fbf50 : 0xffffff802f1e063a 
0xffffff811f6fbfb0 : 0xffffff802eecdd23 
4

1 に答える 1

1

「[your] コードの外側」の意味がよくわからないので、この回答が役に立たない場合は詳しく説明してください。あなたが提供したリテラル コードは機能しますが、実際に失敗したものからそれを減らしたと思いますか?

このコンテキストでは、2 つの問題が考えられます。

割り当ての有効期間

静的変数のメモリは、kext がロードされるときに割り当てられ、アンロードされるときに解放されます。あなたのメモリを使用しているものは何でも、あなたのkextのアンロードを過ぎてそれを使用していないことは確かですか? IOKit kext の場合、パーソナリティの 1 つが一致しない限り、カーネルはロード後すぐに自動的にアンロードします。これは、あなたとあなたのコードが期待するものではないかもしれません。

スレッドの問題

基本的にすべてのカーネル コードはマルチスレッド化されており、エスケープすることはできません。静的/グローバル変数は、競合状態に対して特に脆弱です。あるスレッドがバッファに書き込んでいて、別のスレッドが printf() を介してバッファを読み込もうとしている場合、問題が発生しています。バッファーへのアクセスを適切にシリアライズしていることを確認するか、バッファー メモリを管理するための別の戦略を使用する必要があります。バッファーが一時的なものであると想定される場合、サイズによっては、それらをスタック (static関数内以外)に割り当てることをお勧めします。@ Merlin069 が言及しているように、カーネル スタックは非常に小さい (<16kiB) ため、おそらく数百バイトを超えるものは避けてください。あなたの例の 50 バイトのバッファは、再帰関数でない限り問題ありません。

アップデート:

「私が念頭に置いているのは、静的変数と OSMalloc で割り当てられた変数のメモリ位置の違いです。ctl_enqueuedata() 内のコードで両方にアクセスできますか?」というサブ質問について

はい。

カーネル内で割り当てられたメモリへのアクセスは、通常のプログラムで行うのとほとんど同じです。kernel_task には独自のメモリ マップがあり、カーネル モードで実行中はいつでもアクティブになります。カーネルはモノリシックであるため、ある kext で有効なポインターは別の kext でも有効です。マッピングを明示的に処理する必要があるのは、カーネルからユーザー空間メモリにアクセスする場合、またはユーザー空間からカーネル空間にアクセスする場合のみです。

于 2013-05-09T17:23:14.823 に答える