Cuando la CPU está en modo de usuario, la CPU no puede ejecutar instrucciones privilegiadas y no puede acceder a la memoria de espacio del kernel.
Y cuando la CPU está en modo kernel, la CPU puede ejecutar todas las instrucciones y puede acceder a toda la memoria.
Ahora en Linux, un programa en modo de usuario puede acceder a toda la memoria (usando /dev/mem) y puede ejecutar las dos instrucciones privilegiadas INy OUT(usando iopl()creo).
Entonces, un programa de modo de usuario en Linux puede hacer la mayoría de las cosas (creo que la mayoría de las cosas) que se pueden hacer en modo kernel.
¿No permite que un programa de modo de usuario tenga toda esta potencia frustra el propósito de tener modos de CPU?

ioplno permite todas las instrucciones privilegiadas, por lo que sigue siendo útil para asegurarse de que un programa de espacio de usuario con errores no se ejecute accidentalmenteinvdsaltando a través de un puntero de función dañado que apunta a la memoria ejecutable que comienza con0F 08bytes. Agregué una respuesta con algunas de las razones no relacionadas con la seguridad por las que es útil que los procesos de espacio de usuario eleven sus privilegios.Solo de la misma manera que
modprobe"derrota" la seguridad al cargar código nuevo en el núcleo.Por varias razones, a veces tiene más sentido tener un código semi-privilegiado (como los controladores gráficos dentro del servidor X) ejecutándose en el espacio del usuario en lugar de un hilo del núcleo.
killhacerlo más fácilmente, a menos que bloquee el HW.No hace mucho por la seguridad, pero existen grandes ventajas de fiabilidad y arquitectura de software.
La incorporación de controladores de gráficos al núcleo podría reducir los cambios de contexto entre los clientes X y el servidor X, como un solo usuario-> núcleo-> usuario en lugar de tener que ingresar datos en otro proceso de espacio de uso, pero los servidores X históricamente son demasiado grandes y con errores. quererlos completamente en el núcleo.
Sí, el código malicioso con estos privs podría hacerse cargo del núcleo si así lo deseara, utilizando
/dev/mempara modificar el código del núcleo.O, por ejemplo, en x86, ejecute una
cliinstrucción para deshabilitar las interrupciones en ese núcleo después de hacer unaioplllamada al sistema para establecer su nivel de privilegio de E / S para que suene 0.Pero incluso x86
iopl"solo" da acceso a algunas instrucciones : entrada / salida (y las versiones de cadena ins / outs) y cli / sti. No le permite usarrdmsrowrmsrleer o escribir "registros específicos del modelo" (p. Ej.IA32_LSTARque establece la dirección del punto de entrada del kernel para lasyscallinstrucción x86-64 ), o usarlidtpara reemplazar la tabla de descriptor de interrupción (que le permitiría tomar totalmente sobre la máquina desde el núcleo existente, al menos en ese núcleo).Ni siquiera puede leer los registros de control (como CR3, que contiene la dirección física del directorio de página de nivel superior, que un proceso de ataque puede encontrar útil como compensación
/dev/mempara modificar sus propias tablas de páginas como alternativa ammapmás)/dev/mem. )invd(¡invalidar todas las memorias caché sin reescritura ! ( caso de uso = BIOS anterior antes de que se configure la RAM)) es otra diversión que siempre requiere CPL 0 completo (nivel de privilegio actual), no solo IOPL. Evenwbinvdtiene privilegios porque es muy lento (y no interrumpible) y tiene que vaciar todos los cachés en todos los núcleos. (Consulte ¿Hay alguna forma de vaciar todo el caché de la CPU relacionado con un programa? Y el uso de la instrucción WBINVD )Los errores que resultan en un salto a una dirección incorrecta ejecutando datos como código, por lo tanto, no pueden ejecutar ninguna de estas instrucciones por accidente en un servidor X de espacio de usuario.
El nivel de privilegio actual (en modo protegido y largo) son los 2 bits bajos de
cs(el selector de segmento de código) .mov eax, cs/and eax, 3funciona en cualquier modo para leer el nivel de privilegio.Para escribir el nivel de privilegio, debe hacer
jmp farocall farconfigurarCS:RIP(pero la entrada GDT / LDT para el segmento de destino puede restringirlo según el nivel de privilegio anterior, razón por la cual el espacio de usuario no puede hacer esto para elevarse). O usaintosyscallpara cambiar al anillo 0 en un punto de entrada del núcleo.fuente