2012-05-09 8 views
8

Sé que copy_to_user/copy_from_user, get_user/put_user funciones son para este propósito.¿Cómo acceder a la memoria de espacio de usuario desde el kernel de Linux?

Mi pregunta es que, dada una dirección/puntero de espacio de usuario, ¿cómo puedo acceder a los datos apuntados por la dirección del kernel en general?

Me imagino que primero tengo que asegurarme de que la página que contiene debe estar en la memoria física (en lugar de en el disco).

¿Cuál es el siguiente paso? ¿Puedo usar *p, donde p es el puntero que apunta a algunos datos de espacio del usuario, directamente para referirse a los datos?

¿O primero tengo que invocar kmap para asignar el marco de página físico que contiene al espacio de direcciones virtuales del kernel? ¿Por qué?

Respuesta

4

¡El puntero por sí solo no es suficiente! Necesita saber a qué proceso pertenece el puntero.

Cuando se adelanta el proceso, el puntero apunta al espacio de direcciones de otro proceso. La dirección no se puede mapear más, yadda yadda,

Si ese proceso será el proceso actual al acceder a los datos, entonces debe usar las funciones copy_to_user/copy_from_user.

Si el proceso puede programarse, puede intentar mlock() la página en la RAM y averiguar cuál es la dirección física de la página. Cuando quiera acceder a él, mapea esa página física en una dirección virtual del kernel.

NOTA:

  • Un proceso malicioso puede munlock() la página y engañarle para acceder a una página de memoria RAM mal.
  • No estoy seguro de que la semántica de mlock() exija que la página RAM subrayada NO DEBE cambiar.
  • kernel debería ser capaz de bloquear una página en RAM, no estoy familiarizado con el subsistema mm.
3

La aplicación de espacio de usuario diferente tiene una tabla de página diferente. 1) necesita obtener el programa de espacio de usuario pid. 2) buscar addree en la tabla de la página pid.

A continuación se muestra un código de ejemplo para traducir las direcciones virtuales del espacio de usuario en la dirección física. Funciona en la plataforma 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

Buen punto y la lógica del código es agradable. Pero supongo que hay alguna tabla de hash o una estructura de datos similar que, dada una dirección virtual, te ayuda a ubicar la página física rápidamente. Hay un error: kaddr = __va (paddr); Esta línea solo funciona cuando paddr reside en memoria baja, ¿verdad? – Infinite

+0

paddr significa dirección física, por lo tanto, siempre existió en la memoria. kaddr significa la dirección del kernel. En Linux, kernel define es '#define __va (x) ((void *) ((unsigned long) (x) + PAGE_OFFSET))'. La asignación de la memoria de la dirección del núcleo no es compleja, solo un PAGE_OFFSET. (Debe ser 0xC0000000 en modo x86). Hay otra forma de obtener la dirección. La aplicación de espacio de usuario puede acceder a la dirección del kernel con/proc//pagemap para obtener información de la página. Si puede obtener PFN, también puede obtener la dirección del kernel. – richliu

0

Tendrá que follow una dirección para obtener una estructura page correspondiente (ver follow_page para el ejemplo). Luego, obteniendo la estructura page, necesitará asignarla al espacio de direcciones del núcleo a través de kmap o kmap_atomic.

3

Puede que le sea útil.

Repitamos que el argumento buff para los métodos de lectura y escritura es un puntero de espacio de usuario. Por lo tanto, no se puede desreferenciar directamente con código de kernel.Hay algunas razones para esta restricción:

  • En función de la arquitectura de su conductor se está ejecutando en, y cómo se ha configurado el núcleo , el puntero del espacio de usuario puede no ser válida mientras se ejecuta en modo kernel en todas. Es posible que no haya una asignación para esa dirección , o podría señalar otros datos aleatorios.

  • Incluso si el puntero no significa lo mismo en el espacio del núcleo, la memoria del espacio de usuario se pagina, y la memoria en cuestión podría no ser residente en la memoria RAM cuando se realiza la llamada al sistema. Intentar hacer referencia a directamente la memoria del espacio de usuario podría generar un error de página, que es algo que el código kernel no puede hacer. El resultado sería un "¡Uy!", Que daría como resultado la muerte del proceso que hizo la llamada al sistema.

  • El puntero en cuestión ha sido proporcionado por un programa de usuario, que podría tener errores o ser malicioso. Si su controlador alguna vez desreferencia ciega un puntero proporcionado por el usuario, proporciona una puerta abierta que permite un programa de espacio de usuario para acceder o sobrescribir la memoria en cualquier lugar en el sistema . Si no desea ser responsable de comprometer la seguridad de los sistemas de sus usuarios, nunca podrá desviar un puntero de espacio de usuario directamente.

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

Dicho esto, yo soy yo curiosidad por saber qué ocurre si la dirección del espacio de usuario es realmente válida, y ninguna de las condiciones mencionadas anteriormente ...

Cuestiones relacionadas