doctor descargar operating-system driver

operating-system - descargar - device driver definition



¿Qué son Ring 0 y Ring 3 en el contexto de los sistemas operativos? (3)

He estado aprendiendo conceptos básicos sobre el desarrollo de controladores en Windows. Sigo encontrando los términos Ring 0 y Ring 3 . ¿A qué se refieren estos? ¿Son lo mismo que el modo kernel y el modo usuario ?



Los procesadores Intel (x86 y otros) permiten que las aplicaciones tengan poderes limitados. Para restringir (proteger) los recursos críticos como IO, memoria, puertos, etc., la CPU en contacto con el sistema operativo (Windows en este caso) proporciona niveles de privilegio (siendo 0 el mayor privilegio a 3 siendo el mínimo) que se asignan al modo de kernel y modo de usuario respectivamente.

Por lo tanto, el sistema operativo ejecuta el código del kernel en el anillo 0 (nivel de privilegio más alto (de 0) proporcionado por la CPU) y el código de usuario en el anillo 3

Para obtener más detalles, consulte http://duartes.org/gustavo/blog/post/cpu-rings-privilege-and-protection/


Resumen de uso del anillo de Linux x86

Comprender cómo se usan los anillos en Linux le dará una buena idea de para qué están diseñados.

En el modo protegido x86, la CPU siempre está en uno de los 4 timbres. El kernel de Linux solo usa 0 y 3:

  • 0 para el núcleo
  • 3 para usuarios

Esta es la definición más difícil y rápida de kernel vs userland.

¿Por qué Linux no usa los anillos 1 y 2? Anillos de privilegio de CPU: ¿Por qué los anillos 1 y 2 no se usan?

¿Cómo se determina el anillo actual?

El anillo actual es seleccionado por una combinación de:

  • tabla global de descriptores: una tabla en memoria de las entradas GDT, y cada entrada tiene un campo Privl que codifica el anillo.

    La instrucción LGDT establece la dirección en la tabla de descriptores actual.

    Véase también: http://wiki.osdev.org/Global_Descriptor_Table

  • el segmento registra CS, DS, etc., que apuntan al índice de una entrada en el GDT.

    Por ejemplo, CS = 0 significa que la primera entrada del GDT está actualmente activa para el código en ejecución.

¿Qué puede hacer cada anillo?

El chip de la CPU está construido físicamente de modo que:

  • el anillo 0 puede hacer cualquier cosa

  • el anillo 3 no puede ejecutar varias instrucciones y escribir en varios registros, especialmente:

    • no puede cambiar su propio anillo! De lo contrario, podría ponerse el anillo 0 y los anillos serían inútiles.

      En otras palabras, no se puede modificar el descriptor de segmento actual, que determina el anillo actual.

    • no se pueden modificar las tablas de páginas: ¿cómo funciona la paginación x86?

      En otras palabras, no se puede modificar el registro CR3 y la paginación en sí evita la modificación de las tablas de páginas.

      Esto evita que un proceso vea la memoria de otros procesos por razones de seguridad / facilidad de programación.

    • no se pueden registrar manejadores de interrupciones. Estos se configuran escribiendo en las ubicaciones de memoria, lo que también se evita mediante la paginación.

      Los manejadores se ejecutan en el anillo 0 y romperían el modelo de seguridad.

      En otras palabras, no se pueden usar las instrucciones LGDT y LIDT.

    • no puede hacer instrucciones IO como entrar y out , y por lo tanto tener accesos de hardware arbitrarios.

      De lo contrario, por ejemplo, los permisos de archivos serían inútiles si cualquier programa pudiera leer directamente desde el disco.

      Más precisamente gracias a Michael Petch : en realidad es posible que el sistema operativo permita instrucciones de IO en el anillo 3, esto está controlado por el segmento de estado de Tarea .

      Lo que no es posible es que el anillo 3 se otorgue permiso para hacerlo si no lo tenía en primer lugar.

      Linux siempre lo rechaza. Vea también: ¿Por qué Linux no usa el cambio de contexto de hardware a través del TSS?

¿Cómo hacen los programas y sistemas operativos de transición entre los anillos?

  • cuando la CPU está encendida, comienza a ejecutar el programa inicial en el anillo 0 (bueno, pero es una buena aproximación). Puede pensar que este programa inicial es el kernel (pero normalmente es un cargador de arranque que luego llama al kernel aún en anillo 0).

  • cuando un proceso de usuario quiere que el kernel haga algo por él, como escribir en un archivo, usa una instrucción que genera una interrupción como int 0x80 para señalar el kernel.

    Cuando esto sucede, la CPU llama e interrumpe el controlador de devolución de llamada que el kernel registró en el momento del arranque.

    Este controlador se ejecuta en el anillo 0, que decide si el kernel permitirá esta acción, realiza la acción y reinicia el programa de la zona de usuario en el anillo 3.

    int 0x80 es un mecanismo antiguo y normalmente no se usa más, y fue reemplazado por sysenter y VDSO en x86 y syscall en x86_64.

    Vea esto para un ejemplo mínimo: ¿Qué significa "int 0x80" en el código de ensamblaje?

  • cuando se usa la llamada del sistema exec (o cuando el kernel se iniciará /init ), el kernel prepara los registros y la memoria del nuevo proceso de la zona de usuario, luego salta al punto de entrada y cambia la CPU para que suene 3

  • Si el programa intenta hacer algo malo, como escribir en un registro prohibido o en una dirección de memoria (debido a la paginación), la CPU también llama a algún controlador de devolución de llamada del kernel en el anillo 0.

    Pero como la zona de usuario era traviesa, el núcleo podría matar el proceso esta vez, o darle una advertencia con una señal.

  • Cuando el kernel arranca, configura un reloj de hardware con alguna frecuencia fija, lo que genera interrupciones periódicamente.

    Este reloj de hardware genera interrupciones que ejecutan el anillo 0, y le permite programar qué procesos de usuario para activar.

    De esta manera, la programación puede ocurrir incluso si los procesos no están realizando ninguna llamada al sistema.

¿Cuál es el punto de tener múltiples anillos?

Hay dos ventajas principales de separar kernel y userland:

  • es más fácil hacer programas ya que usted está más seguro de que uno no interferirá con el otro. Por ejemplo, un proceso de usuario no tiene que preocuparse por sobrescribir la memoria de otro programa debido a la paginación, ni por poner el hardware en un estado no válido para otro proceso.
  • es mas seguro Por ejemplo, los permisos de archivo y la separación de memoria podrían impedir que una aplicación de piratería lea sus datos bancarios. Esto supone, por supuesto, que confías en el núcleo.

¿Cómo jugar con eso?

He creado una configuración básica que debería ser una buena manera de manipular los anillos directamente: https://github.com/cirosantilli/x86-bare-metal-examples

Desafortunadamente, no tuve la paciencia para hacer un ejemplo de usuario, pero fui tan lejos como la configuración de paginación, por lo que debería ser factible. Me encantaría ver una solicitud de extracción.

Como alternativa, los módulos del kernel de Linux se ejecutan en el anillo 0, por lo que puede usarlos para probar operaciones privilegiadas, por ejemplo, leer los registros de control: ¿Cómo acceder a los registros de control cr0, cr2, cr3 desde un programa? Obteniendo fallo de segmentación

Aquí está una configuración conveniente QEMU + Buildroot para probarlo sin matar a su anfitrión.

La desventaja de los módulos del kernel es que otros kthreads se están ejecutando y podrían interferir con sus experimentos. Pero en teoría, puede tomar control de todos los controladores de interrupciones con su módulo del kernel y ser dueño del sistema, ese sería un proyecto interesante en realidad.

Anillos negativos

Si bien los anillos negativos no están realmente referenciados en el manual de Intel, en realidad hay modos de CPU que tienen más capacidades que el anillo 0, por lo que son adecuados para el nombre de "anillo negativo".

Un ejemplo es el modo de hipervisor utilizado en la virtualización.

Para más detalles, consulte: https://security.stackexchange.com/questions/129098/what-is-protection-ring-1

BRAZO

En ARM, los anillos se denominan niveles de excepción, pero las ideas principales siguen siendo las mismas.

Existen 4 niveles de excepción en ARMv8, comúnmente utilizados como:

  • EL0: usuario

  • EL1: kernel

  • EL2: hypervisors , por ejemplo Xen .

    Un hipervisor es para un sistema operativo, lo que un sistema operativo es para el usuario.

    El hipervisor registra las devoluciones de llamada para las llamadas de supervisor e inicia el sistema operativo, y luego el sistema operativo realiza llamadas de hipervisor a esas devoluciones de llamada, al igual que el país de usuario realiza llamadas del sistema al sistema operativo.

    Por ejemplo, Xen le permite ejecutar múltiples sistemas operativos como Linux o Windows en el mismo sistema al mismo tiempo, y los aísla entre sí por seguridad y facilidad de depuración, al igual que lo hace Linux para los programas de usuarios.

    Los hipervisores son una parte clave de la infraestructura de nube de hoy: permiten que múltiples servidores se ejecuten en un solo hardware, manteniendo el uso del hardware siempre cerca del 100% y ahorrando mucho dinero.

    AWS, por ejemplo, usó Xen hasta 2017, cuando se mudó a KVM .

  • EL3: otro nivel más. La razón de TODO. ARM Trusted Firmware proporciona una implementación de referencia.

El Modelo de referencia de arquitectura ARMv8 DDI 0487C.a - Capítulo D1 - El Modelo del programador de nivel de sistema AArch64 - La Figura D1-1 ilustra esto de manera hermosa:

Observe cómo ARM, tal vez debido al beneficio de la retrospectiva, tiene una convención de nomenclatura mejor para los niveles de privilegios que x86, sin la necesidad de niveles negativos: 0 es el más bajo y 3 el más alto. Los niveles más altos tienden a ser creados más a menudo que los más bajos.

El EL actual puede consultarse con la instrucción MRS : ¿cuál es el modo de ejecución / nivel de excepción actual, etc.?

ARM no requiere que todos los niveles de excepción estén presentes para permitir implementaciones que no necesitan la función para guardar el área de chip, a costa de una mayor fragmentación del ecosistema. ARMv8 D1.1 "Niveles de excepción" dice:

Una implementación podría no incluir todos los niveles de excepción. Todas las implementaciones deben incluir EL0 y EL1. EL2 y EL3 son opcionales.

QEMU, por ejemplo, tiene como valor predeterminado EL1, pero EL2 y EL3 se pueden habilitar con las opciones de la línea de comandos: qemu-system-aarch64 ingresando el1 al emular el encendido de a53

Las llamadas a los EL superiores, como son las llamadas al sistema del kernel y de usuario, se realizan con las siguientes instrucciones:

  • a EL1: svc (llamada de supervisor) Análogo a syscall en x86_64.
  • a EL2: hvc (llamada de hipervisor)
  • a EL3: smc (llamada de monitor seguro)

hyp llamadas a smc y smc deben seguir la convención oficial de smc .