2012-05-09 4 views
8

Я знаю, что функции copy_to_user/copy_from_user, get_user/put_user предназначены для этой цели.Как получить доступ к памяти пользовательского пространства из ядра Linux?

Вопрос в том, что, учитывая адрес/указатель пространства пользователя, как я могу получить доступ к данным, указанным по адресу из ядра в целом?

Я могу представить, что сначала я должен убедиться, что содержащая страница должна находиться в физической памяти (а не на диске).

Каков следующий шаг? Могу ли я использовать *p, где p - это указатель, указывающий на некоторые данные о пространстве пользователя, непосредственно для обращения к данным?

Или мне нужно сначала вызвать kmap для сопоставления содержащего физического кадра страницы с виртуальным адресным пространством ядра? Зачем?

ответ

4

Указатель не хватает! Вам нужно знать, к какому процессу относится этот указатель.

Когда процесс выгружается, указатель указывает на адресное пространство другого процесса. Адрес, скорее всего, не будет перенаправлен, yadda yadda,

Если этот процесс будет текущим процессом при доступе к данным, вы должны использовать функции copy_to_user/copy_from_user.

Если процесс может быть запланирован, вы можете попытаться выполнить mlock() страницу в ОЗУ и выяснить, какой физический адрес табуляции на странице. Всякий раз, когда вы хотите получить к нему доступ, вы сопоставляете эту физическую страницу с виртуальным адресом ядра.

Примечание:

  • Вредоносный процесс может munlock() страницу и обмануть вас в доступе к неправильной странице RAM.
  • Я не уверен, что семантика mlock() требует, чтобы подчеркивающая страница RAM НЕ ДОЛЖНА меняться.
  • Ядро должно быть в состоянии заблокировать страницу в ОЗУ, я не знаком с подсистемой mm.
3

В другом приложении для пользовательского пространства используется другая таблица страниц. 1) вам нужно получить программу POS для пользовательского пространства. 2) найдите addree в таблице страниц 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); 
+0

Хорошая точка и логика кода хороши. Но я предполагаю, что есть хеш-таблица или подобная структура данных, которая, учитывая виртуальный адрес, помогает быстро найти физическую страницу. Существует недостаток: kaddr = __va (paddr); Эта строка работает только тогда, когда paddr находится в низкой памяти, не так ли? – Infinite

+0

paddr означает физический адрес, поэтому он всегда существовал в памяти. kaddr означает адрес ядра. В ядре Linux define: '#define __va (x) ((void *) ((unsigned long) (x) + PAGE_OFFSET)). Отображение памяти адреса ядра не является сложным, просто PAGE_OFFSET. (Должно быть 0xC0000000 в режиме x86). Существует другой способ получить адрес. Приложение «Пользовательское пространство» может получить доступ к адресу ядра с/proc//pagemap, чтобы получить информацию о странице. Если вы можете получить PFN, он также может получить адрес ядра. – richliu

0

Вам нужно follow адрес, чтобы получить соответствующую page-структуру (см follow_page для примера). Затем, получив структуру page, вам нужно будет сопоставить ее с адресным пространством ядра через kmap или kmap_atomic.

3

Это может оказаться полезным.

Повторим, что аргумент buff для методов чтения и записи является указателем на пользовательский пробел. Поэтому он не может быть непосредственно разыменован кодом ядра .Есть несколько причин для этого ограничения:

  • В зависимости от которой архитектуры драйвер работает на, и как было настроено ядро, указатель пользовательского пространства не может быть действительным, а работает в режиме ядра в все. Не может быть никакого сопоставления для этого адреса , или он может указывать на некоторые другие случайные данные.

  • Даже если указатель действительно означает то же самое, в пространстве ядра, пользовательского пространства памяти выгружаемого, и память о котором идет речь, не может быть в оперативной памяти, когда система вызова. Пытаясь ссылаться на , память пользовательского пространства напрямую могла бы сгенерировать ошибку страницы, которая равна тому, что код ядра не разрешен. Результатом будет «oops», что приведет к гибели процесса, который вызвал системный вызов .

  • Указатель, о котором идет речь, предоставляется программой пользователя, которая может быть ошибкой или вредоносным. Если ваш водитель всегда слепые разыгрывает указатель, предоставляемый пользователем, он предоставляет открытый дверной проем, позволяющий программе пользовательского пространства получать или перезаписывать память в любом месте системы . Если вы не хотите нести ответственность за нарушение безопасности систем пользователей , вы никогда не сможете разыскивать указатель на пользовательский пробел .

Источник: http://www.makelinux.net/ldd3/chp-3-sect-7

Это говорит, я сам хотел бы знать, что происходит, если адрес пользовательского пространства действительно действует, и ни одно из вышеуказанных условий не применяются ...

Смежные вопросы