La implementación de copy_from_user()
depende en gran medida de la arquitectura.
En x86 y x86-64, simplemente hace una lectura directa desde la dirección del espacio de usuario y escribe en la dirección del espacio del kernel, mientras deshabilita temporalmente SMAP (Prevención de acceso en modo supervisor) si está configurado. La parte complicada es que el copy_from_user()
el código se coloca en una región especial para que el controlador de fallas de la página pueda reconocer cuándo ocurre una falla dentro de él. Una falla de protección de memoria que ocurre en copy_from_user()
no elimina el proceso como lo haría si lo desencadena cualquier otro código de contexto de proceso, ni genera pánico en el kernel como lo haría si ocurriera en un contexto de interrupción:simplemente reanuda la ejecución en una ruta de código que devuelve -EFAULT
a la persona que llama.
con respecto a "¿qué hay de copy_to_user ya que el kernel está pasando la dirección del espacio del kernel, cómo puede acceder un proceso de espacio de usuario"
Un proceso de espacio de usuario puede intentar acceder a cualquier dirección. Sin embargo, si la dirección no está asignada en ese espacio de usuario del proceso (es decir, en las tablas de páginas de ese proceso) o si hay un problema con el acceso, como un intento de escritura en una ubicación de solo lectura, se genera un error de página. Tenga en cuenta que al menos en el x86, cada proceso tiene todo el espacio del kernel asignado en el 1 gigabyte más bajo del espacio de direcciones virtuales de ese proceso, mientras que los 3 gigabytes superiores del espacio de direcciones total de 4 GB (estoy usando aquí el clásico de 32 bits caso) se utilizan para el texto del proceso (es decir, el código) y los datos. El código del kernel ejecuta una copia hacia o desde el espacio del usuario en nombre del proceso y, en realidad, es el mapeo de memoria (es decir, tablas de página) de ese proceso que están en uso durante la copia. Esto tiene lugar mientras la ejecución está en modo kernel, es decir, modo privilegiado/supervisor en lenguaje x86. Suponiendo que el código del espacio de usuario haya pasado una ubicación de destino legítima (es decir, una dirección asignada correctamente en ese espacio de direcciones de proceso) para que se copien los datos, copy_to_user , ejecutarse desde el contexto del kernel normalmente podría escribir en esa dirección/región sin problemas y después de que el control regrese al usuario, el espacio del usuario también puede leer desde esta configuración de ubicación por el propio proceso para comenzar. Pueden obtenerse más detalles interesantes se encuentran en los capítulos 9 y 10 de Comprender el kernel de Linux, 3.ª edición, por Daniel P. Bovet, Marco Cesati. En particular, access_ok() es una verificación de validez necesaria pero no suficiente. El usuario aún puede pasar direcciones que no pertenecen al espacio de direcciones del proceso. En este caso, se producirá una excepción de error de página mientras el código del núcleo ejecuta la copia. La parte más interesante es cómo el controlador de fallas de la página del kernel determina que la falla de la página en tal caso no se debe a un error en el código del kernel, sino a una dirección incorrecta del usuario (especialmente si el código del kernel en cuestión es de un módulo del kernel). cargado).