Pregunta

Considere un controlador para Linux que utiliza get_user_pages (o get_page) para mapear páginas del proceso invocador. La dirección física de las páginas a continuación, se pasa a un dispositivo de hardware. Tanto el proceso como el dispositivo puede leer y escribir en las páginas hasta que las partes deciden poner fin a la comunicación. En particular, la comunicación puede seguir utilizando las páginas después de la llamada al sistema que llama vuelve get_user_pages. La llamada al sistema es, en efecto, la creación de un zona de memoria compartida entre el proceso y el dispositivo de hardware .

Me preocupa lo que sucede si las llamadas de procesos fork (que podría ser de otro hilo, y podría ocurrir ya sea mientras la llamada al sistema que las llamadas get_user_pages está en curso o posterior). En particular, si el padre escribe en el área de memoria compartida después de que el tenedor, lo sé yo de la dirección física subyacente (presumiblemente cambiado debido a copy-on-write)? Quiero entender:

  1. cuáles son las necesidades del núcleo que se pueden hacer para defenderse de un proceso potencialmente porta mal (no quiero crear un Seguridad agujero!);
  2. ¿Qué restricciones a la necesidad proceso de obedecer para que el funcionalidad de nuestra controlador funciona correctamente (es decir, los restos de memoria física mapeados en la misma dirección en el proceso padre).

    • Idealmente, me gustaría que el caso común en que el proceso hijo no utiliza nuestro conductor en absoluto (es probable que llama exec casi de inmediato) de trabajo.
    • Idealmente, el proceso padre debe no tiene que tomar ninguna medida especial al asignar la memoria, como hemos código que pasa un búfer de pila-asignado al controlador existente.
    • Soy consciente de madvise con MADV_DONTFORK, y que estaría bien tener la memoria desaparece desde el espacio del proceso hijo, pero no es aplicable a un búfer de pila asignados.
    • “No utilice tenedor mientras tiene una conexión activa con nuestro conductor” sería molesto, pero aceptable como último recurso si el punto 1 es satisfecha.

Estoy dispuesto a ser señalado a la documentación o el código fuente. He mirado en particular en controladores Linux , pero no encontró esta cuestión que se aborda. RTFS aplica incluso sólo a la parte correspondiente de la fuente del kernel es abrumadora un poco.

La versión del núcleo no está completamente fijo, sino que es reciente (digamos =2.6.26). Estamos solamente apuntan a plataformas ARM (de un solo procesador multinúcleo hasta ahora, pero está a la vuelta de la esquina), si es importante.

¿Fue útil?

Solución

A fork() no interferirá con get_user_pages():. get_user_pages() le dará una struct page

Se necesitaría kmap() que antes de poder acceder a él, y esta asignación se hace en el espacio del núcleo, no el espacio de usuario.

EDIT:. get_user_pages() toque la tabla de páginas, pero no debe preocuparse acerca de esto (que sólo asegúrese de que las páginas se asignan en el espacio de usuario), y vuelve -EFAULT si no tuviera ningún problema hacerlo

Si fork (), hasta que se realice la copia en escritura, el niño será capaz de ver esa página. Una vez que se hace la copia por escritura (porque el niño / la conductor / el padre escribió a la página a través de la asignación de espacio de usuario - no es el kmap kernel () el conductor tiene), ya no será compartida esa página. Si todavía mantiene una kmap () en la página (en el código del controlador), usted no será capaz de saber si usted está sosteniendo la página padre o del niño.

1) No es un problema de seguridad, porque una vez que execve (), todo eso se ha ido.

2) Cuando la horquilla () que desea tanto proceso sea idéntica (Es un tenedor !!). Me gustaría pensar que su diseño debe permitir que tanto el padre y el niño tenga acceso al controlador. Execve () hará que se vacíe todo.

¿Qué pasa con la adición de algunas funciones en el espacio de usuario como:

 f = open("/dev/your_thing")
 mapping = mmap(f, ...)

Cuando mmap () se llama en su dispositivo, se instala un mapeo de memoria, con banderas especiales: http://os1a.cs.columbia.edu/lxr /source/include/linux/mm.h#071

Usted tiene algunas cosas interesantes como:

#define VM_SHARED       0x00000008
#define VM_LOCKED       0x00002000
#define VM_DONTCOPY     0x00020000      /* Do not copy this vma on fork */

VM_SHARED desactivará copiar al escribir VM_LOCKED desactivará el intercambio de esa página VM_DONTCOPY le dirá al núcleo no copiar la región VMA de tenedor, aunque no creo que sea una buena idea

Otros consejos

La respuesta corta es utilizar madvise(addr, len, MADV_DONTFORK) en cualquier búfer de espacio de usuario le da a su conductor. Esto le dice al núcleo que la asignación no debe ser copiada de padres a hijos y por lo tanto no hay ninguna vaca.

El inconveniente es que el niño hereda ninguna asignación en esa dirección, por lo que si desea que el niño a continuación, empezar a utilizar el conductor tendrá que volver a asignar esa memoria. Pero eso es bastante fácil de hacer en el espacio de usuario.

Actualizar . Un buffer en la pila es problemático, no estoy seguro de que puede hacerlo seguro en general

No se puede marcarlo DONTFORK, debido a que su hijo podría estar en ejecución en esa página de la pila cuando se bifurca, o (peor de una manera) que podría hacer un retorno de la función más tarde y golpear la página de pila sin asignar. (Incluso probado esto, puede marcar feliz su DONTFORK pila, las cosas malas suceden cuando la horquilla).

La otra manera de evitar una vaca es la creación de un mapeo compartida, pero no se puede asignar su pila compartida por razones obvias.

Eso significa que se arriesga a una vaca si el tenedor. Incluso si el niño "sólo" los ejecutivos aún podría tocar la página pila y causar una vaca, lo que lleva a los padres conseguir una página diferente, lo cual es malo.

El punto de menor importancia en su favor es que el código utilizando una pila en la memoria intermedia sólo tiene que preocuparse sobre el código que llama se bifurcan, es decir. no se puede utilizar un buffer en la pila después de la función ha regresado. Por lo que sólo necesita para auditar sus receptores de llamadas, y si nunca se bifurcan son seguros, pero que todavía puede ser factible, y es frágil si el código cambia nunca.

creo que realmente quiere tener toda la memoria que se le da a su conductor que venir de un asignador de costumbre en el espacio de usuario. No debería ser tan intrusivo. El asignador cualquiera puede mmap su dispositivo directamente, como el otro Respuesta posible, o simplemente utilizar mmap anónima, madvise(DONTFORK), y probablemente mlock() a cabo intercambio de evitar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top