En informática , un microkernel (a menudo abreviado como μ-kernel ) es la cantidad casi mínima de software que puede proporcionar los mecanismos necesarios para implementar un sistema operativo (OS). Estos mecanismos incluyen la gestión del espacio de direcciones de bajo nivel , la gestión de subprocesos y la comunicación entre procesos (IPC).
Si el hardware proporciona múltiples anillos o modos de CPU , el microkernel puede ser el único software que se ejecuta en el nivel más privilegiado, que generalmente se conoce como modo supervisor o kernel . Las funciones tradicionales del sistema operativo, como los controladores de dispositivos , las pilas de protocolos y los sistemas de archivos , generalmente se eliminan del propio microkernel y, en su lugar, se ejecutan en el espacio de usuario . [1]
En términos del tamaño del código fuente, los microkernels suelen ser más pequeños que los kernels monolíticos . El microkernel MINIX 3 , por ejemplo, tiene sólo aproximadamente 12.000 líneas de código. [2]
Los microkernels tienen sus raíces en el pionero informático danés Per Brinch Hansen y su permanencia en la empresa informática danesa Regnecentralen , donde dirigió los esfuerzos de desarrollo de software para el ordenador RC 4000. [3] En 1967, Regnecentralen estaba instalando un prototipo RC 4000 en la planta de fertilizantes Zakłady Azotowe Puławy en Polonia. El ordenador utilizaba un pequeño sistema operativo en tiempo real adaptado a las necesidades de la planta. Brinch Hansen y su equipo se preocuparon por la falta de generalidad y reutilización del sistema RC 4000. Temían que cada instalación requiriera un sistema operativo diferente, por lo que comenzaron a investigar formas novedosas y más generales de crear software para el RC 4000. [4] En 1969, su esfuerzo dio como resultado la finalización del Sistema de multiprogramación RC 4000. Su núcleo proporcionaba comunicación entre procesos basada en el paso de mensajes para hasta 23 procesos sin privilegios, de los cuales 8 a la vez estaban protegidos entre sí. Además, implementó la programación de franjas de tiempo de programas ejecutados en paralelo, el inicio y control de la ejecución de programas a petición de otros programas en ejecución y el inicio de transferencias de datos hacia o desde periféricos. Aparte de estos mecanismos elementales, no tenía una estrategia incorporada para la ejecución de programas y la asignación de recursos. Esta estrategia debía implementarse mediante una jerarquía de programas en ejecución en la que los procesos principales tenían control completo sobre los procesos secundarios y actuaban como sus sistemas operativos. [5] [6]
Siguiendo el trabajo de Brinch Hansen, los microkernels se han desarrollado desde los años 70. [7] El término microkernel apareció por primera vez no más tarde de 1981. [8] Los microkernels fueron pensados como una respuesta a los cambios en el mundo de la informática y a varios desafíos para adaptar los " monokernels " existentes a estos nuevos sistemas. Nuevos controladores de dispositivos, pilas de protocolos, sistemas de archivos y otros sistemas de bajo nivel se desarrollaban todo el tiempo. Este código normalmente se encontraba en el núcleo monolítico y, por lo tanto, requería un trabajo considerable y una gestión cuidadosa del código para trabajar en él. Los microkernels se desarrollaron con la idea de que todos estos servicios se implementarían como programas de espacio de usuario, como cualquier otro, lo que permitiría trabajar en ellos de forma monolítica e iniciarlos y detenerlos como cualquier otro programa. Esto no solo permitiría trabajar con estos servicios más fácilmente, sino que también separaría el código del núcleo para permitir que se ajustara con precisión sin preocuparse por efectos secundarios no deseados. Además, permitiría que se "construyeran" sistemas operativos completamente nuevos sobre un núcleo común, lo que ayudaría a la investigación de sistemas operativos.
Los microkernels fueron un tema muy candente en la década de 1980, cuando se introdujeron las primeras redes de área local utilizables. [ cita requerida ] . El kernel AmigaOS Exec fue un ejemplo temprano, introducido en 1986 y utilizado en una PC con relativo éxito comercial. La falta de protección de memoria, considerada en otros aspectos un defecto, permitió que este kernel tuviera un rendimiento de paso de mensajes muy alto porque no necesitaba copiar datos mientras intercambiaba mensajes entre programas de espacio de usuario. [9]
Los mismos mecanismos que permitieron que el núcleo se distribuyera en el espacio de usuario también permitieron que el sistema se distribuyera a través de enlaces de red. Los primeros micronúcleos, en particular Mach creado por Richard Rashid , demostraron tener un rendimiento decepcionante, pero las ventajas inherentes parecían tan grandes que se convirtió en una importante línea de investigación hasta finales de la década de 1990. [10] Sin embargo, durante este tiempo la velocidad de las computadoras creció enormemente en relación con los sistemas de red, y las desventajas en el rendimiento llegaron a abrumar las ventajas en términos de desarrollo. [ cita requerida ]
Se hicieron muchos intentos de adaptar los sistemas existentes para tener un mejor rendimiento, pero la sobrecarga siempre fue considerable y la mayoría de estos esfuerzos requirieron que los programas del espacio de usuario se movieran nuevamente al núcleo. Para el año 2000, la mayoría de los esfuerzos del núcleo Mach a gran escala habían terminado, aunque macOS de Apple , lanzado en 2001, todavía usa un núcleo híbrido llamado XNU , que combina un núcleo Mach de OSF/1 muy modificado (híbrido) ( núcleo OSFMK 7.3) con código de BSD UNIX, [11] [12] y este núcleo también se usa en iOS , tvOS y watchOS . Windows NT , comenzando con NT 3.1 y continuando con Windows 11 , usa un diseño de núcleo híbrido. A partir de 2012 , GNU Hurd basado en Mach también es funcional y se incluye en las versiones de prueba de Arch Linux y Debian .[actualizar]
Aunque el trabajo principal sobre los micronúcleos había terminado en gran medida, los experimentadores continuaron con el desarrollo. [ cita requerida ] Desde entonces se ha demostrado que muchos de los problemas de rendimiento de los diseños anteriores no eran una limitación fundamental del concepto, sino que se debían al deseo del diseñador de utilizar sistemas de propósito único para implementar tantos de estos servicios como fuera posible. [ cita requerida ] El uso de un enfoque más pragmático para el problema, incluido el código ensamblador y confiando en el procesador para aplicar conceptos normalmente admitidos en el software, condujo a una nueva serie de micronúcleos con un rendimiento drásticamente mejorado.
Los microkernels están estrechamente relacionados con los exokernels . [13] También tienen mucho en común con los hipervisores , [14] pero estos últimos no pretenden ser mínimos y están especializados en soportar máquinas virtuales ; el microkernel L4 frecuentemente se utiliza en una capacidad de hipervisor.
Los primeros núcleos de los sistemas operativos eran bastante pequeños, en parte porque la memoria de la computadora era limitada. A medida que la capacidad de las computadoras crecía, también lo hacía la cantidad de dispositivos que el núcleo debía controlar. A lo largo de la historia inicial de Unix , los núcleos eran generalmente pequeños, aunque contenían varios controladores de dispositivos e implementaciones de sistemas de archivos . Cuando los espacios de direcciones aumentaron de 16 a 32 bits, el diseño del núcleo ya no estaba limitado por la arquitectura del hardware y los núcleos comenzaron a crecer.
La distribución de software Berkeley (BSD) de Unix inició la era de los núcleos más grandes. Además de operar un sistema básico que constaba de la CPU, los discos y las impresoras, BSD agregó un sistema de red TCP/IP completo y una serie de dispositivos "virtuales" que permitían que los programas existentes funcionaran de manera "invisible" en la red. Este crecimiento continuó durante muchos años, lo que dio como resultado núcleos con millones de líneas de código fuente . Como resultado de este crecimiento, los núcleos eran propensos a errores y se volvieron cada vez más difíciles de mantener.
El microkernel fue pensado para abordar este crecimiento de los kernels y las dificultades que surgieron de él. En teoría, el diseño del microkernel permite una gestión más sencilla del código debido a su división en servicios de espacio de usuario . Esto también permite una mayor seguridad y estabilidad como resultado de la menor cantidad de código que se ejecuta en modo kernel . Por ejemplo, si un servicio de red fallara debido a un desbordamiento de búfer , solo se dañaría la memoria del servicio de red, dejando el resto del sistema aún funcional.
La comunicación entre procesos (IPC) es cualquier mecanismo que permite que procesos separados se comuniquen entre sí, generalmente mediante el envío de mensajes . La memoria compartida es, estrictamente definida, también un mecanismo de comunicación entre procesos, pero la abreviatura IPC generalmente se refiere solo al paso de mensajes, y es esto último lo que es particularmente relevante para los microkernels. IPC permite que el sistema operativo se construya a partir de una serie de programas más pequeños llamados servidores, que son utilizados por otros programas en el sistema, invocados a través de IPC. La mayor parte o la totalidad del soporte para hardware periférico se maneja de esta manera, con servidores para controladores de dispositivos, pilas de protocolos de red , sistemas de archivos, gráficos, etc.
La IPC puede ser sincrónica o asincrónica. La IPC asincrónica es análoga a la comunicación en red: el remitente envía un mensaje y continúa ejecutándose. El receptor verifica ( sondea ) la disponibilidad del mensaje, o es alertado de ello mediante algún mecanismo de notificación. La IPC asincrónica requiere que el núcleo mantenga buffers y colas para los mensajes, y se ocupa de los desbordamientos de buffer; también requiere una doble copia de los mensajes (del remitente al núcleo y del núcleo al receptor). En la IPC sincrónica, la primera parte (el remitente o el receptor) bloquea hasta que la otra parte esté lista para realizar la IPC. No requiere almacenamiento en buffer ni copias múltiples, pero el encuentro implícito puede hacer que la programación sea complicada. La mayoría de los programadores prefieren el envío asincrónico y la recepción sincrónica.
Los microkernels de primera generación generalmente admitían IPC sincrónico y asincrónico, y sufrían de un rendimiento IPC deficiente. Jochen Liedtke asumió que el diseño e implementación de los mecanismos IPC eran la razón subyacente de este bajo rendimiento. En su microkernel L4 fue pionero en métodos que redujeron los costos de IPC en un orden de magnitud . [15] Estos incluyen una llamada al sistema IPC que admite una operación de envío y recepción, haciendo que todo IPC sea sincrónico y pasando la mayor cantidad de datos posible en registros. Además, Liedtke introdujo el concepto de cambio de proceso directo , donde durante una ejecución de IPC se realiza un cambio de contexto (incompleto) del remitente directamente al receptor. Si, como en L4, parte o todo el mensaje se pasa en registros, esto transfiere la parte en el registro del mensaje sin ninguna copia. Además, se evita la sobrecarga de invocar el planificador; Esto es especialmente beneficioso en el caso común en el que un cliente utiliza IPC en un estilo de llamada a procedimiento remoto (RPC) al invocar un servidor. Otra optimización, llamada programación diferida , evita recorrer colas de programación durante IPC al dejar los subprocesos que se bloquean durante IPC en la cola de listos. Una vez que se invoca al planificador, mueve dichos subprocesos a la cola de espera adecuada. Como en muchos casos un subproceso se desbloquea antes de la siguiente invocación del planificador, este enfoque ahorra trabajo significativo. Desde entonces, QNX y MINIX 3 han adoptado enfoques similares . [ cita requerida ]
En una serie de experimentos, Chen y Bershad compararon los ciclos de memoria por instrucción (MCPI) del Ultrix monolítico con los del microkernel Mach combinado con un servidor Unix 4.3BSD que se ejecutaba en el espacio de usuario . Sus resultados explicaron el peor rendimiento de Mach mediante un MCPI más alto y demostraron que el IPC por sí solo no es responsable de gran parte de la sobrecarga del sistema, lo que sugiere que las optimizaciones centradas exclusivamente en el IPC tendrán un efecto limitado. [16] Liedtke luego refinó los resultados de Chen y Bershad al hacer una observación de que la mayor parte de la diferencia entre el MCPI de Ultrix y Mach se debía a las fallas de capacidad de caché y concluyó que reducir drásticamente el conjunto de trabajo de caché de un microkernel resolverá el problema. [17]
En un sistema cliente-servidor, la mayor parte de la comunicación es esencialmente sincrónica, incluso si se utilizan primitivas asincrónicas, ya que la operación típica es un cliente que invoca a un servidor y luego espera una respuesta. Como también se presta a una implementación más eficiente, la mayoría de los microkernels generalmente siguieron el ejemplo de L4 y solo proporcionaron una primitiva IPC sincrónica. La IPC asincrónica podría implementarse sobre la base de subprocesos auxiliares. Sin embargo, la experiencia ha demostrado que la utilidad de la IPC sincrónica es dudosa: la IPC sincrónica fuerza un diseño multiproceso en sistemas que de otro modo serían simples, con las complejidades de sincronización resultantes. Además, una invocación de servidor similar a RPC secuencia al cliente y al servidor, lo que debería evitarse si se ejecutan en núcleos separados. Por lo tanto, las versiones de L4 implementadas en productos comerciales han considerado necesario agregar un mecanismo de notificación asincrónica para brindar un mejor soporte a la comunicación asincrónica. Este mecanismo similar a una señal no transporta datos y, por lo tanto, no requiere almacenamiento en búfer por parte del núcleo. Al tener dos formas de IPC, no obstante han violado el principio de minimalidad. Otras versiones de L4 han cambiado completamente al IPC asincrónico. [18]
Como el IPC sincrónico bloquea a la primera parte hasta que la otra esté lista, el uso sin restricciones podría fácilmente llevar a bloqueos. Además, un cliente podría fácilmente montar un ataque de denegación de servicio en un servidor enviando una solicitud y nunca intentando recibir la respuesta. Por lo tanto, el IPC sincrónico debe proporcionar un medio para evitar el bloqueo indefinido. Muchos microkernels proporcionan tiempos de espera en las llamadas IPC, que limitan el tiempo de bloqueo. En la práctica, elegir valores de tiempo de espera razonables es difícil, y los sistemas casi inevitablemente usan tiempos de espera infinitos para clientes y tiempos de espera cero para servidores. Como consecuencia, la tendencia es a no proporcionar tiempos de espera arbitrarios, sino solo un indicador que indica que el IPC debe fallar inmediatamente si el socio no está listo. Este enfoque proporciona efectivamente una opción de los dos valores de tiempo de espera de cero e infinito. Las versiones recientes de L4 y MINIX han seguido este camino (las versiones anteriores de L4 usaban tiempos de espera). QNX evita el problema al requerir que el cliente especifique el búfer de respuesta como parte de la llamada de envío de mensajes. Cuando el servidor responde, el núcleo copia los datos al buffer del cliente, sin tener que esperar a que el cliente reciba la respuesta explícitamente. [19]
Los servidores de microkernel son esencialmente programas demonio como cualquier otro, excepto que el kernel otorga a algunos de ellos privilegios para interactuar con partes de la memoria física que de otro modo estarían fuera del alcance de la mayoría de los programas. Esto permite que algunos servidores, en particular los controladores de dispositivos, interactúen directamente con el hardware.
Un conjunto básico de servidores para un microkernel de propósito general incluye servidores de sistema de archivos, servidores de controladores de dispositivos, servidores de red, servidores de pantalla y servidores de dispositivos de interfaz de usuario. Este conjunto de servidores (extraído de QNX ) proporciona aproximadamente el conjunto de servicios ofrecidos por un núcleo monolítico de Unix . Los servidores necesarios se inician al iniciar el sistema y brindan servicios, como acceso a archivos, redes y dispositivos, a programas de aplicación comunes. Con dichos servidores ejecutándose en el entorno de una aplicación de usuario, el desarrollo de servidores es similar al desarrollo de aplicaciones comunes, en lugar del proceso de compilación y arranque necesario para el desarrollo del núcleo.
Además, muchos "fallos" se pueden corregir simplemente deteniendo y reiniciando el servidor . Sin embargo, parte del estado del sistema se pierde con el servidor que falla, por lo que este enfoque requiere que las aplicaciones se enfrenten a la falla. Un buen ejemplo es un servidor responsable de las conexiones TCP/IP : si se reinicia este servidor, las aplicaciones experimentarán una conexión "perdida", una ocurrencia normal en un sistema en red. Para otros servicios, la falla es menos esperada y puede requerir cambios en el código de la aplicación. Para QNX, la capacidad de reinicio se ofrece como el kit de herramientas de alta disponibilidad de QNX. [20]
Los controladores de dispositivos frecuentemente realizan acceso directo a memoria (DMA) y, por lo tanto, pueden escribir en ubicaciones arbitrarias de la memoria física, incluidas varias estructuras de datos del núcleo. Por lo tanto, estos controladores deben ser confiables. Es un error común pensar que esto significa que deben ser parte del núcleo. De hecho, un controlador no es inherentemente más o menos confiable por ser parte del núcleo.
Si bien ejecutar un controlador de dispositivo en el espacio de usuario no necesariamente reduce el daño que puede causar un controlador que se comporta mal, en la práctica es beneficioso para la estabilidad del sistema en presencia de controladores defectuosos (en lugar de maliciosos): las violaciones de acceso a la memoria por parte del código del controlador en sí (a diferencia del dispositivo) aún pueden ser detectadas por el hardware de administración de memoria. Además, muchos dispositivos no son compatibles con DMA, sus controladores pueden volverse no confiables al ejecutarlos en el espacio de usuario. Recientemente, una cantidad cada vez mayor de computadoras cuentan con IOMMUs , muchas de las cuales se pueden usar para restringir el acceso de un dispositivo a la memoria física. [21] Esto también permite que los controladores en modo usuario dejen de ser confiables.
Los controladores en modo usuario son anteriores a los micronúcleos. En 1967, el Michigan Terminal System (MTS) admitía controladores en el espacio de usuario (incluido su soporte para sistemas de archivos), el primer sistema operativo diseñado con esa capacidad. [22] Históricamente, los controladores eran un problema menor, ya que la cantidad de dispositivos era pequeña y confiable de todos modos, por lo que tenerlos en el núcleo simplificaba el diseño y evitaba posibles problemas de rendimiento. Esto condujo al estilo tradicional de controlador en el núcleo de Unix, [23] Linux y Windows NT. Con la proliferación de varios tipos de periféricos, la cantidad de código de controlador aumentó y en los sistemas operativos modernos domina al núcleo en tamaño de código.
Como un microkernel debe permitir la creación de servicios de sistema operativo arbitrarios, debe proporcionar alguna funcionalidad básica. Como mínimo, esto incluye:
Este diseño minimalista fue iniciado por Nucleus de Brinch Hansen y el hipervisor de VM de IBM . Desde entonces se ha formalizado en el principio de minimalismo de Liedtke :
Un concepto se tolera dentro del micronúcleo sólo si moverlo fuera del núcleo, es decir, permitir implementaciones competitivas, impediría la implementación de la funcionalidad requerida del sistema. [17]
Todo lo demás se puede hacer en un programa en modo de usuario, aunque los controladores de dispositivos implementados como programas de usuario pueden, en algunas arquitecturas de procesador, requerir privilegios especiales para acceder al hardware de E/S.
Relacionado con el principio de minimalidad, e igualmente importante para el diseño de microkernel, está la separación de mecanismo y política , es lo que permite la construcción de sistemas arbitrarios sobre un kernel mínimo. Cualquier política incorporada al kernel no puede sobrescribirse a nivel de usuario y, por lo tanto, limita la generalidad del microkernel. [13] La política implementada en servidores a nivel de usuario se puede cambiar reemplazando los servidores (o dejando que la aplicación elija entre servidores que compiten y ofrecen servicios similares).
Para mayor eficiencia, la mayoría de los microkernels contienen programadores y administran temporizadores, en violación del principio de minimidad y el principio de separación entre políticas y mecanismos.
El arranque de un sistema basado en microkernel requiere controladores de dispositivos , que no son parte del kernel. Normalmente, esto significa que están empaquetados con el kernel en la imagen de arranque, y el kernel admite un protocolo de arranque que define cómo se ubican e inician los controladores; este es el procedimiento de arranque tradicional de los microkernels L4 . Algunos microkernels simplifican esto colocando algunos controladores clave dentro del kernel (en violación del principio de minimalidad), LynxOS y el Minix original son ejemplos. Algunos incluso incluyen un sistema de archivos en el kernel para simplificar el arranque. Un sistema basado en microkernel puede arrancar a través de un cargador de arranque compatible con arranque múltiple. Dichos sistemas generalmente cargan servidores vinculados estáticamente para realizar un arranque inicial o montan una imagen del sistema operativo para continuar con el arranque.
Un componente clave de un microkernel es un buen diseño del sistema IPC y del administrador de memoria virtual que permita implementar el manejo de fallas de página y el intercambio en servidores de modo usuario de una manera segura. Dado que todos los servicios son realizados por programas de modo usuario, es esencial contar con medios eficientes de comunicación entre programas, mucho más que en los núcleos monolíticos. El diseño del sistema IPC es lo que hace o deshace un microkernel. Para ser efectivo, el sistema IPC no solo debe tener una sobrecarga baja, sino también interactuar bien con la programación de la CPU.
En la mayoría de los procesadores convencionales, obtener un servicio es inherentemente más costoso en un sistema basado en microkernel que en un sistema monolítico. [13] En el sistema monolítico, el servicio se obtiene mediante una única llamada al sistema, que requiere dos cambios de modo (cambios del anillo del procesador o del modo de la CPU ). En el sistema basado en microkernel, el servicio se obtiene enviando un mensaje IPC a un servidor y obteniendo el resultado en otro mensaje IPC del servidor. Esto requiere un cambio de contexto si los controladores se implementan como procesos, o una llamada de función si se implementan como procedimientos. Además, pasar datos reales al servidor y viceversa puede generar una sobrecarga de copia adicional, mientras que en un sistema monolítico el kernel puede acceder directamente a los datos en los búferes del cliente.
Por lo tanto, el rendimiento es un problema potencial en los sistemas de microkernel. La experiencia con microkernels de primera generación como Mach y ChorusOS mostró que los sistemas basados en ellos tenían un rendimiento muy deficiente. [16] Sin embargo, Jochen Liedtke demostró que los problemas de rendimiento de Mach eran el resultado de un diseño e implementación deficientes, específicamente la excesiva huella de caché de Mach . [17] Liedtke demostró con su propio microkernel L4 que mediante un diseño e implementación cuidadosos, y especialmente siguiendo el principio de minimalidad, los costos de IPC podrían reducirse en más de un orden de magnitud en comparación con Mach. El rendimiento de IPC de L4 aún es imbatible en una variedad de arquitecturas. [24] [25] [26]
Si bien estos resultados demuestran que el bajo rendimiento de los sistemas basados en microkernels de primera generación no es representativo de los kernels de segunda generación, como L4, esto no constituye una prueba de que se puedan construir sistemas basados en microkernels con un buen rendimiento. Se ha demostrado que un servidor Linux monolítico portado a L4 exhibe solo un pequeño porcentaje de sobrecarga en comparación con Linux nativo. [27] Sin embargo, un sistema de un solo servidor de este tipo exhibe pocas, si es que presenta alguna, de las ventajas que se supone que brindan los microkernels al estructurar la funcionalidad del sistema operativo en servidores separados.
Existen varios sistemas comerciales multiservidor, en particular los sistemas en tiempo real QNX e Integrity . No se ha publicado ninguna comparación exhaustiva del rendimiento en relación con los sistemas monolíticos para estos sistemas multiservidor. Además, el rendimiento no parece ser la preocupación principal de estos sistemas comerciales, que en cambio enfatizan tiempos de respuesta de manejo de interrupciones rápidos y confiables (QNX) y simplicidad en aras de la robustez. Un intento de construir un sistema operativo multiservidor de alto rendimiento fue el proyecto IBM Sawmill Linux. [28] Sin embargo, este proyecto nunca se completó.
Mientras tanto, se ha demostrado que los controladores de dispositivos a nivel de usuario pueden acercarse al rendimiento de los controladores en el núcleo incluso para dispositivos de alto rendimiento y alta interrupción como Gigabit Ethernet. [29] Esto parece implicar que son posibles sistemas multiservidor de alto rendimiento.
Los beneficios de seguridad de los microkernels han sido discutidos frecuentemente. [30] [31] En el contexto de la seguridad, el principio de minimalidad de los microkernels es, según algunos han argumentado, una consecuencia directa del principio de mínimo privilegio , según el cual todo el código debe tener solo los privilegios necesarios para proporcionar la funcionalidad requerida. La minimalidad requiere que la base de computación confiable (TCB) de un sistema se mantenga mínima. Como el kernel (el código que se ejecuta en el modo privilegiado del hardware) tiene acceso no verificado a cualquier dato y, por lo tanto, puede violar su integridad o confidencialidad, el kernel siempre es parte de la TCB. Minimizarlo es natural en un diseño impulsado por la seguridad.
En consecuencia, los diseños de microkernel se han utilizado para sistemas diseñados para aplicaciones de alta seguridad, incluidos KeyKOS , EROS y sistemas militares. De hecho, los criterios comunes (CC) en el nivel de garantía más alto ( Evaluation Assurance Level (EAL) 7) tienen un requisito explícito de que el objetivo de la evaluación sea "simple", un reconocimiento de la imposibilidad práctica de establecer una verdadera confiabilidad para un sistema complejo. Una vez más, el término "simple" es engañoso y está mal definido. Al menos, los Criterios de evaluación de sistemas informáticos de confianza del Departamento de Defensa introdujeron un lenguaje algo más preciso en las clases B3/A1:
"El TCB deberá implementar mecanismos de protección completos, conceptualmente simples y con una semántica definida con precisión. Una parte importante de la ingeniería del sistema deberá estar orientada a minimizar la complejidad del TCB, así como a excluir del TCB aquellos módulos que no sean críticos para la protección".
— Criterios de evaluación de sistemas informáticos de confianza del Departamento de Defensa
En 2018, un artículo presentado en la Conferencia de Sistemas de Asia y el Pacífico afirmó que los microkernels eran demostrablemente más seguros que los kernels monolíticos al investigar todos los CVE críticos publicados para el kernel de Linux en ese momento. El estudio concluyó que el 40% de los problemas podrían no ocurrir en absoluto en un microkernel verificado formalmente, y solo el 4% de los problemas permanecerían totalmente sin mitigar en un sistema de ese tipo. [32]
Los trabajos más recientes sobre microkernels se han centrado en las especificaciones formales de la API del kernel y en las pruebas formales de las propiedades de seguridad de la API y de la corrección de la implementación. El primer ejemplo de esto es una prueba matemática de los mecanismos de confinamiento en EROS, basada en un modelo simplificado de la API de EROS. [33] Más recientemente (en 2007) se realizó un conjunto completo de pruebas comprobadas por máquina de las propiedades del modelo de protección de seL4 , una versión de L4. [34]
Esto ha dado lugar a lo que se conoce como microkernels de tercera generación , [35] caracterizados por una API orientada a la seguridad con acceso a los recursos controlado por capacidades , la virtualización como una preocupación de primera clase, enfoques novedosos para la gestión de recursos del kernel, [36] y un objetivo de diseño de idoneidad para el análisis formal , además del objetivo habitual de alto rendimiento. Algunos ejemplos son Coyotos, seL4 , Nova, [37] [38] Redox y Fiasco.OC. [37] [39]
En el caso de seL4, se ha logrado una verificación formal completa de la implementación, [35] es decir, una prueba matemática de que la implementación del núcleo es consistente con su especificación formal. Esto proporciona una garantía de que las propiedades probadas sobre la API realmente se cumplen para el núcleo real, un grado de seguridad que va más allá incluso de CC EAL7. A esto le siguieron pruebas de las propiedades de cumplimiento de la seguridad de la API y una prueba que demostraba que el código binario ejecutable es una traducción correcta de la implementación de C, sacando al compilador del TCB. En conjunto, estas pruebas establecen una prueba de extremo a extremo de las propiedades de seguridad del núcleo. [40]
Algunos ejemplos de microkernels son:
El término nanokernel o picokernel históricamente se refería a:
También hay al menos un caso en el que el término nanokernel se utiliza para referirse no a un núcleo pequeño, sino a uno que admite una resolución de reloj de nanosegundos . [41]
{{cite book}}
: Mantenimiento de CS1: falta la ubicación del editor ( enlace ){{cite journal}}
: CS1 maint: varios nombres: lista de autores ( enlace )-la referencia básica confiable.{{cite journal}}
: CS1 maint: varios nombres: lista de autores ( enlace )– la referencia básica de Mach.