2012-05-09 36 views
8

知っているのは、copy_to_user/copy_from_userget_user/put_userの機能です。Linuxカーネルからユーザー空間のメモリにアクセスするには?

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

私が最初に私が含まれているページが物理メモリ(代わりのディスクで)であるべきことを確認する必要があることを想像することができます。

次のステップは何ですか? *pを使用することができます。pは、データを参照するために、いくつかのユーザー空間データを指すポインターですか?

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

答えて

4

ポインタだけでは不十分です!そのポインタが "所属する"プロセスを知る必要があります。プロセスが別のプロセスのアドレス空間に、ポインタポイントを差し替えられます

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

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

注:

  • 悪質なプロセスは、()のページをmunlockの、間違ったRAMのページにアクセスするにあなたをだますことができます。
  • mlock()セマンティクスでは、下線を引くRAMページを変更してはいけません。
  • カーネルはページをRAMにロックできるはずですが、私はmmサブシステムに慣れていません。
3

異なるユーザースペースアプリケーションのページテーブルが異なります。 1)ユーザー空間プログラムpidを取得する必要があります。 2)pidのページテーブルでaddreeを検索します。以下は

ユーザ空間の仮想アドレスのは、物理アドレスに変換するためのサンプルコードです。 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); 
+0

...私はユーザ空間のアドレスが実際に有効であり、上記の条件のいずれも適用されない場合は何が起こるかを知って自分自身が好奇心、と述べました良い点とコードのロジックがいいです。しかし、仮想アドレスを指定すると、物理ページをすばやく見つけるのに役立つハッシュテーブルや同様のデータ構造があると思います。欠陥があります:kaddr = __va(paddr);この行は、paddrが低メモリに常駐する場合にのみ有効です。 – Infinite

+0

paddrは物理アドレスを意味するので、常にメモリに存在します。 kaddrはカーネルアドレスを意味します。 Linuxのカーネル定義では '#define __va(x)((void *)((unsigned long)(x)+ PAGE_OFFSET))'が定義されています。カーネルアドレスのメモリマッピングは複雑ではなく、ちょうどPAGE_OFFSETです。 (x86モードで0xC0000000である必要があります)。 アドレスを取得する他の方法があります。ユーザー空間アプリケーションは、カーネルアドレスに/ proc//pagemapでアクセスしてページ情報を取得できます。 PFNを取得できる場合は、カーネルアドレスも取得できます。 – richliu

0

あなたは(例えばfollow_pageを参照)followに対応page構造体を取得するためのアドレスが必要になります。次に、page構造体を取得するには、kmapまたはkmap_atomicを介してカーネルのアドレス空間にマップする必要があります。

3

これは便利です。

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

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

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

  • は、バグまたは悪意のあるユーザープログラムによって提供されています。あなたのドライバーが ユーザー提供のポインターを盲目的に参照解除すると、 ユーザー空間プログラムが システム内の任意の場所にアクセスしたり上書きしたりすることができます。ユーザーのシステムの セキュリティを侵害することに責任を負うことを望まない場合は、 ユーザー空間ポインタを直接参照解除することはできません。

出典:http://www.makelinux.net/ldd3/chp-3-sect-7

関連する問題