En informática , los dominios de protección jerárquica , [1] [2] a menudo llamados anillos de protección , son mecanismos para proteger datos y funcionalidades contra fallas (al mejorar la tolerancia a fallas ) y comportamiento malicioso (al brindar seguridad informática ).
Los sistemas operativos de las computadoras proporcionan diferentes niveles de acceso a los recursos. Un anillo de protección es uno de los dos o más niveles jerárquicos o capas de privilegio dentro de la arquitectura de un sistema informático . Esto generalmente se aplica mediante hardware mediante algunas arquitecturas de CPU que proporcionan diferentes modos de CPU a nivel de hardware o microcódigo . Los anillos se organizan en una jerarquía desde el más privilegiado (el más confiable, generalmente numerado cero) hasta el menos privilegiado (el menos confiable, generalmente con el número de anillo más alto). En la mayoría de los sistemas operativos, el anillo 0 es el nivel con más privilegios e interactúa más directamente con el hardware físico, como cierta funcionalidad de la CPU (por ejemplo, los registros de control) y los controladores de E/S.
Se proporcionan mecanismos especiales para permitir que un anillo externo acceda a los recursos de un anillo interno de una manera predefinida, en lugar de permitir un uso arbitrario. La restricción correcta del acceso entre anillos puede mejorar la seguridad al evitar que los programas de un anillo o nivel de privilegio hagan un mal uso de los recursos destinados a los programas de otro. Por ejemplo, se debe evitar que el software espía que se ejecuta como un programa de usuario en el Anillo 3 encienda una cámara web sin informar al usuario, ya que el acceso al hardware debe ser una función del Anillo 1 reservada para los controladores de dispositivos . Los programas como los navegadores web que se ejecutan en anillos con números más altos deben solicitar acceso a la red, un recurso restringido a un anillo con un número más bajo.
X86S, una arquitectura Intel publicada recientemente, solo tiene anillo 0 y anillo 3. Los anillos 1 y 2 se eliminarán en X86S ya que los sistemas operativos modernos nunca los utilizan. [3]
Los anillos de protección múltiples fueron uno de los conceptos más revolucionarios introducidos por el sistema operativo Multics , un predecesor altamente seguro de la familia de sistemas operativos Unix de la actualidad. El ordenador central GE 645 tenía cierto control de acceso al hardware, incluidos los mismos dos modos que tenían las otras máquinas de la serie GE-600, y permisos a nivel de segmento en su unidad de gestión de memoria ("Unidad de anexión"), pero eso no era suficiente para proporcionar soporte completo para anillos en hardware, por lo que Multics los admitía atrapando transiciones de anillo en software; [4] su sucesor, el Honeywell 6180 , los implementó en hardware, con soporte para ocho anillos; [5] Los anillos de protección en Multics estaban separados de los modos de CPU; el código en todos los anillos excepto el anillo 0, y parte del código del anillo 0, se ejecutaban en modo esclavo. [6]
Sin embargo, la mayoría de los sistemas de propósito general utilizan sólo dos anillos, incluso si el hardware en el que se ejecutan ofrece más modos de CPU que ese. Por ejemplo, Windows 7 y Windows Server 2008 (y sus predecesores) utilizan sólo dos anillos, donde el anillo 0 corresponde al modo kernel y el anillo 3 al modo usuario [7] , porque las versiones anteriores de Windows NT se ejecutaban en procesadores que admitían sólo dos niveles de protección. [8]
Muchas arquitecturas de CPU modernas (incluida la popular arquitectura Intel x86 ) incluyen alguna forma de protección de anillo, aunque el sistema operativo Windows NT , como Unix, no utiliza completamente esta característica. OS/2 , hasta cierto punto, utiliza tres anillos: [9] anillo 0 para código de kernel y controladores de dispositivos, anillo 2 para código privilegiado (programas de usuario con permisos de acceso de E/S) y anillo 3 para código no privilegiado (casi todos los programas de usuario). Bajo DOS , el kernel, los controladores y las aplicaciones normalmente se ejecutan en el anillo 3 (sin embargo, esto es exclusivo del caso en el que se utilizan controladores de modo protegido o extensores DOS; como un sistema operativo de modo real, el sistema se ejecuta sin protección efectiva), mientras que los administradores de memoria 386 como EMM386 se ejecutan en el anillo 0. Además de esto, DR-DOS ' EMM386 3.xx puede ejecutar opcionalmente algunos módulos (como DPMS ) en el anillo 1. OpenVMS utiliza cuatro modos llamados (en orden de privilegios decrecientes) Kernel, Ejecutivo, Supervisor y Usuario.
Un renovado interés en esta estructura de diseño surgió con la proliferación del software Xen VMM , la discusión en curso sobre núcleos monolíticos versus micro núcleos (particularmente en grupos de noticias de Usenet y foros web ), la estructura de diseño Ring-1 de Microsoft como parte de su iniciativa NGSCB y los hipervisores basados en virtualización x86 como Intel VT-x (anteriormente Vanderpool).
El sistema Multics original tenía ocho anillos, pero muchos sistemas modernos tienen menos. El hardware conoce en todo momento el anillo actual del hilo de instrucción en ejecución, con la ayuda de un registro de máquina especial. En algunos sistemas, a las áreas de memoria virtual se les asignan números de anillo en el hardware. Un ejemplo es el Data General Eclipse MV/8000 , en el que los tres primeros bits del contador de programa (PC) servían como registro de anillo. De este modo, el código que se ejecuta con el PC virtual establecido en 0xE200000, por ejemplo, estaría automáticamente en el anillo 7, y llamar a una subrutina en una sección diferente de la memoria provocaría automáticamente una transferencia de anillo.
El hardware restringe severamente las formas en que se puede pasar el control de un anillo a otro, y también impone restricciones sobre los tipos de acceso a la memoria que se pueden realizar entre anillos. Usando x86 como ejemplo, hay una estructura de compuerta especial [ aclaración necesaria ] a la que hace referencia la instrucción de llamada que transfiere el control de una manera segura [ aclaración necesaria ] hacia puntos de entrada predefinidos en anillos de nivel inferior (más confiables); esto funciona como una llamada de supervisor en muchos sistemas operativos que usan la arquitectura de anillo. Las restricciones de hardware están diseñadas para limitar las oportunidades de violaciones de seguridad accidentales o maliciosas. Además, el anillo más privilegiado puede tener capacidades especiales (como direccionamiento de memoria real que omite el hardware de memoria virtual).
La arquitectura de la versión 7 de ARM implementa tres niveles de privilegios: aplicación (PL0), sistema operativo (PL1) e hipervisor (PL2). De manera inusual, el nivel 0 (PL0) es el nivel con menos privilegios, mientras que el nivel 2 es el nivel con más privilegios. [10] La versión 8 de ARM implementa cuatro niveles de excepción: aplicación (EL0), sistema operativo (EL1), hipervisor (EL2) y monitor seguro/firmware (EL3), para AArch64 [11] : D1-2454 y AArch32. [11] : G1-6013
La protección de anillo se puede combinar con los modos de procesador (modo maestro/núcleo/privilegiado/supervisor versus modo esclavo/sin privilegios/usuario) en algunos sistemas. Los sistemas operativos que se ejecutan en hardware compatible con ambos pueden utilizar ambas formas de protección o solo una.
El uso eficaz de la arquitectura de anillos requiere una estrecha cooperación entre el hardware y el sistema operativo. [¿ Por qué? ] Los sistemas operativos diseñados para funcionar en múltiples plataformas de hardware pueden hacer un uso limitado de los anillos si no están presentes en todas las plataformas compatibles. A menudo, el modelo de seguridad se simplifica a "núcleo" y "usuario", incluso si el hardware proporciona una granularidad más fina a través de los anillos.
En términos informáticos, el modo supervisor es una bandera mediada por hardware que puede ser modificada por el código que se ejecuta en el software a nivel de sistema. Las tareas o subprocesos a nivel de sistema pueden [a] tener esta bandera activada mientras se ejecutan, mientras que las aplicaciones a nivel de usuario no la tendrán. Esta bandera determina si sería posible ejecutar operaciones de código de máquina, como modificar registros para varias tablas de descriptores, o realizar operaciones como deshabilitar interrupciones. La idea de tener dos modos diferentes para operar proviene de "cuanto más poder, más responsabilidad": se confía en que un programa en modo supervisor nunca falle, ya que una falla puede hacer que todo el sistema informático se bloquee.
El modo supervisor es "un modo de ejecución en algunos procesadores que permite la ejecución de todas las instrucciones, incluidas las instrucciones privilegiadas. También puede dar acceso a un espacio de direcciones diferente, al hardware de gestión de memoria y a otros periféricos. Este es el modo en el que normalmente se ejecuta el sistema operativo". [12]
En un núcleo monolítico , el sistema operativo se ejecuta en modo supervisor y las aplicaciones en modo usuario. Otros tipos de sistemas operativos , como los que tienen un exokernel o un microkernel , no necesariamente comparten este comportamiento.
Algunos ejemplos del mundo de la PC:
La mayoría de los procesadores tienen al menos dos modos diferentes. Los procesadores x86 tienen cuatro modos diferentes divididos en cuatro anillos diferentes. Los programas que se ejecutan en el anillo 0 pueden hacer cualquier cosa con el sistema, y el código que se ejecuta en el anillo 3 debería poder fallar en cualquier momento sin afectar al resto del sistema informático. Los anillos 1 y 2 rara vez se utilizan, pero se pueden configurar con diferentes niveles de acceso.
En la mayoría de los sistemas existentes, cambiar del modo usuario al modo kernel tiene un alto costo asociado en rendimiento. Se ha medido, en la solicitud básica getpid
, que cuesta entre 1000 y 1500 ciclos en la mayoría de las máquinas. De estos, solo alrededor de 100 son para el cambio real (70 del espacio de usuario al espacio kernel y 40 de vuelta), el resto es "sobrecarga del kernel". [13] [14] En el microkernel L3 , la minimización de esta sobrecarga redujo el costo general a alrededor de 150 ciclos. [13]
Maurice Wilkes escribió: [15]
... Finalmente, se hizo evidente que la protección jerárquica que proporcionaban los anillos no se ajustaba a los requisitos del programador del sistema y aportaba poca o ninguna mejora con respecto al sistema simple de tener sólo dos modos. Los anillos de protección se prestaban a una implementación eficiente en hardware, pero no había mucho más que decir al respecto. [...] El atractivo de la protección de grano fino se mantuvo, incluso después de que se vio que los anillos de protección no proporcionaban la respuesta... Esto resultó ser nuevamente un callejón sin salida...
Para ganar rendimiento y determinismo, algunos sistemas colocan funciones que probablemente se considerarían como lógica de aplicación, en lugar de controladores de dispositivos, en modo kernel; se citan como ejemplos las aplicaciones de seguridad ( control de acceso , cortafuegos , etc.) y los monitores de sistemas operativos. Al menos un sistema de gestión de bases de datos integrado, e X treme DB Kernel Mode , se ha desarrollado específicamente para la implementación en modo kernel, para proporcionar una base de datos local para funciones de aplicación basadas en kernel y para eliminar los cambios de contexto que de otro modo se producirían cuando las funciones del kernel interactúan con un sistema de base de datos que se ejecuta en modo de usuario. [16]
A veces, las funciones también se mueven a través de anillos en la dirección opuesta. El núcleo Linux, por ejemplo, inyecta en los procesos una sección vDSO que contiene funciones que normalmente requerirían una llamada al sistema, es decir, una transición de anillo. En lugar de realizar una llamada al sistema, estas funciones utilizan datos estáticos proporcionados por el núcleo. Esto evita la necesidad de una transición de anillo y, por lo tanto, es más liviano que una llamada al sistema. La función gettimeofday se puede proporcionar de esta manera.
Las CPU recientes de Intel y AMD ofrecen instrucciones de virtualización x86 para que un hipervisor controle el acceso al hardware del Anillo 0. Aunque son mutuamente incompatibles, tanto Intel VT-x (nombre en código "Vanderpool") como AMD-V (nombre en código "Pacifica") permiten que un sistema operativo invitado ejecute operaciones del Anillo 0 de forma nativa sin afectar a otros invitados ni al sistema operativo anfitrión.
Antes de la virtualización asistida por hardware , los sistemas operativos invitados se ejecutaban bajo el anillo 1. Cualquier intento que requiera un nivel de privilegio más alto para realizarse (anillo 0) producirá una interrupción y luego se manejará mediante software, llamado "Trap and Emulate".
Para ayudar a la virtualización y reducir la sobrecarga causada por la razón anterior, VT-x y SVM permiten que el invitado se ejecute en el anillo 0. VT-x presenta la operación raíz/no raíz de VMX: el hipervisor se ejecuta en el modo de operación raíz de VMX, que posee el privilegio más alto. El sistema operativo invitado se ejecuta en el modo de operación no raíz de VMX, lo que les permite operar en el anillo 0 sin tener privilegios de hardware reales. La operación no raíz de VMX y las transiciones de VMX están controladas por una estructura de datos llamada control de máquina virtual. [17] VT-x permite que el hipervisor y el sistema operativo invitado se ejecuten en el anillo 0, lo que hace que "Trap and Emulate" sea obsoleto, lo que mejora el rendimiento de la virtualización.
Un nivel de privilegio en el conjunto de instrucciones x86 controla el acceso del programa que se está ejecutando actualmente en el procesador a recursos como regiones de memoria, puertos de E/S e instrucciones especiales. Hay 4 niveles de privilegio que van desde 0, que es el más privilegiado, hasta 3, que es el menos privilegiado. La mayoría de los sistemas operativos modernos utilizan el nivel 0 para el núcleo/ejecutivo y el nivel 3 para los programas de aplicación. Cualquier recurso disponible para el nivel n también está disponible para los niveles 0 a n, por lo que los niveles de privilegio son anillos. Cuando un proceso con menos privilegios intenta acceder a un proceso con más privilegios, se informa al sistema operativo una excepción de falla de protección general .
No es necesario utilizar los cuatro niveles de privilegio. Los sistemas operativos actuales con una amplia cuota de mercado, incluidos Microsoft Windows , macOS , Linux , iOS y Android, utilizan principalmente un mecanismo de paginación con un solo bit para especificar el nivel de privilegio como Supervisor o Usuario (U/S Bit). Windows NT utiliza el sistema de dos niveles. [18] Los programas de modo real en 8086 se ejecutan en el nivel 0 (nivel de privilegio más alto), mientras que el modo virtual en 8086 ejecuta todos los programas en el nivel 3. [19]
Los usos futuros potenciales para los múltiples niveles de privilegios admitidos por la familia ISA x86 incluyen la contenedorización y las máquinas virtuales . Un núcleo del sistema operativo anfitrión podría usar instrucciones con acceso de privilegio completo ( modo kernel ), mientras que las aplicaciones que se ejecutan en el sistema operativo invitado en una máquina virtual o contenedor podrían usar el nivel más bajo de privilegios en modo usuario. El núcleo de la máquina virtual y del sistema operativo invitado podrían usar un nivel intermedio de privilegio de instrucción para invocar y virtualizar operaciones en modo kernel, como llamadas del sistema desde el punto de vista del sistema operativo invitado. [20]
El indicador IOPL ( nivel de privilegio de E/S ) es un indicador que se encuentra en todas las CPU x86 compatibles con IA-32 . Ocupa los bits 12 y 13 en el registro FLAGS . En modo protegido y modo largo , muestra el nivel de privilegio de E/S del programa o tarea actual. El nivel de privilegio actual (CPL) (CPL0, CPL1, CPL2, CPL3) de la tarea o programa debe ser menor o igual que el IOPL para que la tarea o programa acceda a los puertos de E/S .
La IOPL se puede cambiar usando POPF(D)
y IRET(D)
solo cuando el nivel de privilegio actual es Ring 0.
Además de IOPL, los permisos del puerto de E/S en el TSS también participan en la determinación de la capacidad de una tarea para acceder a un puerto de E/S.
En los sistemas x86, la virtualización de hardware x86 ( VT-x y SVM ) se conoce como "ring −1", el modo de administración del sistema se conoce como "ring −2", el motor de administración Intel y el procesador de seguridad de plataforma AMD a veces se conocen como "ring −3". [21]
Muchas arquitecturas de hardware de CPU proporcionan mucha más flexibilidad de la que explotan los sistemas operativos que normalmente ejecutan. El uso adecuado de modos de CPU complejos requiere una cooperación muy estrecha entre el sistema operativo y la CPU, y por lo tanto tiende a vincular el SO a la arquitectura de la CPU. Cuando el SO y la CPU están diseñados específicamente el uno para el otro, esto no es un problema (aunque algunas características del hardware pueden quedar sin explotar), pero cuando el SO está diseñado para ser compatible con múltiples arquitecturas de CPU diferentes, una gran parte de las características del modo de CPU pueden ser ignoradas por el SO. Por ejemplo, la razón por la que Windows usa solo dos niveles (ring 0 y ring 3) es que algunas arquitecturas de hardware que fueron compatibles en el pasado (como PowerPC o MIPS ) implementaron solo dos niveles de privilegio. [7]
Multics era un sistema operativo diseñado específicamente para una arquitectura de CPU especial (que a su vez fue diseñada específicamente para Multics) y aprovechaba al máximo los modos de CPU disponibles para él. Sin embargo, era una excepción a la regla. Hoy en día, este alto grado de interoperabilidad entre el sistema operativo y el hardware no suele ser rentable, a pesar de las posibles ventajas para la seguridad y la estabilidad.
En definitiva, el propósito de los distintos modos operativos de la CPU es proporcionar protección al hardware contra la corrupción accidental o deliberada del entorno del sistema (y las correspondientes violaciones de la seguridad del sistema) por parte del software. Sólo las partes "confiables" del software del sistema pueden ejecutarse en el entorno sin restricciones del modo kernel y, en los diseños paradigmáticos, sólo cuando sea absolutamente necesario. El resto del software se ejecuta en uno o más modos de usuario. Si un procesador genera una condición de error o excepción en un modo de usuario, en la mayoría de los casos la estabilidad del sistema no se ve afectada; si un procesador genera una condición de error o excepción en el modo kernel, la mayoría de los sistemas operativos detendrán el sistema con un error irrecuperable. Cuando existe una jerarquía de modos (seguridad basada en anillos), los errores y excepciones en un nivel de privilegio pueden desestabilizar sólo los niveles de privilegio de número superior. Por lo tanto, un error en el anillo 0 (el modo kernel con el privilegio más alto) bloqueará todo el sistema, pero un error en el anillo 2 sólo afectará a los anillos 3 y posteriores y al propio anillo 2, como máximo.
Las transiciones entre modos quedan a discreción del hilo en ejecución cuando la transición es de un nivel de privilegio alto a uno de privilegio bajo (como del modo kernel al modo usuario), pero las transiciones de niveles de privilegio inferiores a superiores solo pueden tener lugar a través de "puertas" seguras controladas por hardware que se atraviesan ejecutando instrucciones especiales o cuando se reciben interrupciones externas.
Los sistemas operativos microkernel intentan minimizar la cantidad de código que se ejecuta en modo privilegiado, por motivos de seguridad y elegancia , pero en última instancia sacrifican el rendimiento.
que Windows utiliza sólo dos niveles es que algunas arquitecturas de hardware que eran compatibles en el pasado (como Compaq Alpha y Silicon Graphics MIPS ) implementaron sólo dos niveles de privilegios.