10

copy_to_user/ copy_from_userget_user/put_user関数がこの目的のためのものであることは知っています。

私の質問は、ユーザー空間のアドレス/ポインターが与えられた場合、一般に、カーネルからアドレスが指すデータにどのようにアクセスできますか?

最初に、含まれているページが (ディスクではなく) 物理メモリにあることを確認する必要があると想像できます。

次のステップは何ですか?*pどこかのユーザー空間データを指しているポインターを使用pして、データを直接参照できますか?

それとも、最初に呼び出しkmapて、含まれている物理ページ フレームをカーネルの仮想アドレス空間にマップする必要がありますか? なんで?

4

4 に答える 4

6

これは便利かもしれません。

read および write メソッドへの buff 引数がユーザー空間ポインターであることを繰り返しましょう。したがって、カーネル コードで直接逆参照することはできません。この制限にはいくつかの理由があります。

  • ドライバーが実行されているアーキテクチャ、およびカーネルの構成方法によっては、カーネル モードでの実行中にユーザー空間ポインターがまったく有効にならない場合があります。そのアドレスのマッピングがないか、他のランダム データを指している可能性があります。

  • ポインターがカーネル空間で同じことを意味する場合でも、ユーザー空間のメモリはページングされ、システム コールが行われたときに問題のメモリが RAM に常駐していない可能性があります。ユーザー空間メモリを直接参照しようとすると、ページ フォールトが発生する可能性がありますが、これはカーネル コードでは許可されていません。結果は「おっと」となり、システム コールを行ったプロセスが終了します。

  • 問題のポインターはユーザー プログラムによって提供されたものであり、バグや悪意がある可能性があります。ドライバーがユーザー指定のポインターをやみくもに逆参照する場合、ユーザー空間プログラムがシステム内の任意の場所のメモリにアクセスまたは上書きできるようにするオープンドアが提供されます。ユーザーのシステムのセキュリティを侵害する責任を負いたくない場合は、ユーザー空間ポインターを直接逆参照することはできません。

ソース: http://www.makelinux.net/ldd3/chp-3-sect-7

そうは言っても、ユーザー空間アドレスが実際に有効で、上記の条件のいずれも当てはまらない場合に何が起こるか知りたいです...

于 2012-05-10T09:42:58.037 に答える
4

ポインターだけでは十分ではありません。ポインターが「属する」プロセスを知る必要があります。

プロセスがプリエンプトされると、ポインターは別のプロセスのアドレス空間を指します。アドレスはもうマッピングされていない可能性があります、yadda yadda、

データにアクセスするときにそのプロセスが現在のプロセスになる場合は、copy_to_user/copy_from_user 関数を使用する必要があります。

プロセスがスケジュールされている可能性がある場合は、RAM でページを mlock() してみて、ページの物理 RAM アドレスがどれかを調べることができます。アクセスしたいときはいつでも、その物理ページをカーネル仮想アドレスにマップします。

ノート:

  • 悪意のあるプロセスがページを munlock() して、間違った RAM ページにアクセスするように仕向ける可能性があります。
  • mlock() セマンティクスが下線の RAM ページを変更してはならないことを要求するかどうかはわかりません。
  • カーネルはページを RAM にロックできるはずです。私は mm サブシステムに詳しくありません。
于 2012-05-09T08:17:06.237 に答える
3

ユーザー空間アプリケーションが異なれば、ページ テーブルも異なります。

  1. ユーザー空間のプログラム pid を取得する必要があります。
  2. pid のページ テーブルでアドレスを検索します。

以下は、ユーザー空間の仮想アドレスを物理アドレスに変換するサンプル コードです。x86 プラットフォームで動作します。

taskpid = find_get_pid(curpid);
task = pid_task(taskpid, PIDTYPE_PID );
mm = get_task_mm(task);
down_read(&mm->mmap_sem);

start_vaddr = vaddr;
end_vaddr = 0xC0000000;

while( start_vaddr < end_vaddr){
    u32 end;

    end = (( start_vaddr + PMD_SIZE) & PMD_MASK);

    if( end < start_vaddr || end > end_vaddr)
        end = end_vaddr;

    ret = walk_pgd(start_vaddr, end, mm);
    if(ret != 0){
        printk("ret: %08x \n", ret);
        break;
    }

    start_vaddr = end;

}

up_read(&mm->mmap_sem);

paddr = ret;
kaddr = __va(paddr);
mmput(mm);
于 2012-05-09T16:15:17.180 に答える
1

follow対応する構造体を取得するにはアドレスが必要ですpage(例についてはfollow_pageを参照してください)。次に、またはpageを介し​​てカーネルのアドレス空間にマップするために必要な構造体を取得します。kmapkmap_atomic

于 2012-05-09T23:44:52.180 に答える