CAPÍTULO 14 · PARTE II

CPU, instrucciones, privilegios y cambio de contexto

Cómo una CPU transforma instrucciones en estado, cómo los niveles de privilegio limitan operaciones y por qué un cambio de contexto no equivale a una autorización ni a un simple salto al kernel.

Nivel N1–N2 · Estado published

Cuando una instrucción cruza una frontera

Un proceso recibe una entrada que no debería poder leer. El resultado depende de algo más profundo que una regla visible en la aplicación: qué instrucciones puede ejecutar el procesador, qué estado conserva la CPU, en qué nivel de privilegio se ejecuta el código y cómo se transfiere el control entre un programa y el sistema operativo. Si se mezclan esas capas, una explicación de seguridad suele atribuir al hardware una decisión que tomó el kernel, o al kernel una propiedad que nunca tuvo la CPU.

Este capítulo construye un modelo operativo de cuatro elementos relacionados: instrucción, estado de CPU, privilegio y cambio de contexto. No pretende enseñar una arquitectura concreta ni convertir una lista de registros en un manual de ensamblador. La pregunta es otra: ¿qué mecanismo impide que una secuencia de instrucciones ordinarias haga cualquier cosa, cómo se habilita una operación protegida y qué información debe conservarse al cambiar de ejecución?

El modelo será deliberadamente explícito sobre sus límites. Una CPU impone comprobaciones y transiciones; no conoce por sí sola qué usuario tiene derecho a leer un expediente, qué solicitud pertenece a un tenant ni si una operación satisface la misión de un servicio. Esas decisiones se construyen encima, con políticas, memoria, kernel y aplicación. Entender la frontera evita dos errores profesionales: tratar «modo kernel» como sinónimo de «autorizado» y tratar un cambio de contexto como si fuera únicamente guardar unos registros.

Estado: qué significa que una CPU esté ejecutando

Una instrucción es una operación codificada que una arquitectura de conjunto de instrucciones (Instruction Set Architecture, ISA) define para el software. La ISA especifica, entre otras cosas, qué operandos acepta una instrucción, cómo modifica registros o memoria, cómo cambia el contador de programa y qué excepciones puede producir. La microarquitectura es la implementación interna que ejecuta esa especificación: tuberías, cachés, predicción y unidades funcionales pueden cambiar sin que cambie la semántica visible de la ISA.

El estado mínimo que permite describir una ejecución incluye un program counter (PC), que identifica la próxima instrucción; registros generales para valores y direcciones; un stack pointer (SP), cuando la convención de ejecución usa una pila; indicadores o flags; y, en arquitecturas con protección, registros o estructuras que participan en la traducción y autorización de accesos. Los nombres concretos cambian entre x86-64, AArch64 y otras ISAs. Lo estable es la relación: el procesador obtiene una instrucción a partir del estado actual, calcula su efecto y deja un estado nuevo.

Podemos escribir una transición abstracta como estado_n + instrucción_n → estado_n+1 o, si algo no puede completarse, estado_n + evento → entrada en un manejador. La notación no dice cómo se implementa el circuito; obliga a preguntar qué cambió. Si un load lee una dirección, cambia un registro y avanza el PC, el dato leído y la dirección efectiva pertenecen al efecto de la instrucción. Si una comprobación de permisos falla, la operación no se convierte en una lectura parcial legítima: se produce una excepción definida por la arquitectura y el control pasa a una ruta protegida.

La diferencia entre representación y ejecución es importante. Un volcado puede contener bytes que parecen instrucciones, pero sólo lo son cuando el PC y el modo de decodificación los tratan como código. Un mismo patrón puede representar operaciones diferentes en otra ISA, en otro modo o como datos. Una cadena encontrada en memoria no demuestra ejecución: hay que enlazarla con control de flujo, permisos, registros y evidencia temporal.

Del fetch al efecto observable

Desde estado e instrucción, una comprobación satisfecha produce un nuevo estado; una comprobación no satisfecha produce un evento arquitectónico y una entrada definida por la ISA.
La ejecución normal y la entrada por excepción son resultados alternativos de reglas arquitectónicas.

El esquema no representa una ISA concreta ni una decisión de autorización de negocio.

El ciclo conceptual suele describirse como fetch, decodificación, ejecución y actualización de estado. En fetch, la CPU obtiene bytes desde una dirección asociada al PC. La decodificación determina la operación y los operandos. La ejecución calcula un resultado, accede a memoria o solicita una transición. Finalmente se escriben registros, flags y el PC siguiente. Las implementaciones modernas solapan muchas instrucciones, pero el contrato de la ISA conserva un orden arquitectónico observable.

Ese orden arquitectónico no equivale a un orden de todos los efectos físicos: cachés y predicción pueden dejar señales microarquitectónicas aunque una instrucción especulativa se descarte. Un permiso arquitectónico correctamente impuesto no elimina por sí solo ese tipo de observación.

Un error común es leer un fragmento de ensamblador como una narración completa. mov puede copiar un valor, no «leer un archivo»; una instrucción de salto puede cambiar el control, no demostrar que el destino es alcanzable; un registro cargado con un identificador no prueba que una política lo validara. El significado de una instrucción depende de la convención de llamada, el estado previo, los mapeos de memoria y las comprobaciones que ocurren antes o después. La CPU aporta semántica elemental, no el contrato completo de la aplicación.

Privilegio: qué puede impedir la CPU

El privilegio es el conjunto de condiciones arquitectónicas que determina si una ejecución puede realizar ciertas operaciones o acceder a ciertos recursos. Las arquitecturas proporcionan mecanismos distintos. x86 define niveles de protección que la práctica de sistemas suele presentar como ring 0 y ring 3; AArch64 emplea niveles de excepción como EL0 para aplicaciones y EL1 para el sistema operativo. No son traducciones exactas entre sí, pero ambos diseños permiten distinguir código ordinario de código con autoridad arquitectónica ampliada.

Una instrucción puede ser no privilegiada y aun así fallar por protección de memoria. Otra puede requerir un nivel concreto porque modifica registros de control, configuración de traducción, interrupciones o dispositivos. El procesador evalúa el nivel actual y las reglas arquitectónicas aplicables; ante una infracción genera una excepción o aborta la operación según la especificación. La consecuencia de seguridad es una frontera mecánica: una aplicación no debería poder convertir por sí misma una instrucción ordinaria en una operación de control del sistema.

La frontera no es una política de negocio. El hardware no sabe si principal-17 pertenece a la organización A, si puede modificar una factura o si el motivo de una solicitud es legítimo. El kernel puede representar esas decisiones mediante credenciales, descriptores, namespaces u otros objetos, y la aplicación puede añadir autorización contextual. Que el kernel se ejecute con mayor privilegio sólo significa que puede realizar operaciones protegidas y aplicar decisiones; no demuestra que cada decisión que tome sea correcta.

También conviene separar privilegio arquitectónico de autoridad concedida por el sistema operativo. Un proceso en modo usuario puede poseer un descriptor o handle que le permite operar sobre un objeto, o una credencial con un privilegio específico del sistema operativo. Ninguno de esos casos convierte al proceso en código de kernel. A la inversa, un componente de kernel puede ejecutar instrucciones privilegiadas y aun así estar sujeto a una política interna. El término capability se reserva aquí para mecanismos que el sistema denomina así —por ejemplo, las Linux capabilities—; no se usa como sinónimo genérico de descriptor o permiso.

Un acceso protegido paso a paso

Supongamos un programa de usuario que ejecuta una instrucción de carga sobre una dirección no disponible en su espacio. La CPU calcula la dirección y las reglas de traducción y permisos provocan una excepción de página o protección. El kernel recibe el evento e inspecciona el contexto. Si puede resolverlo —por ejemplo, materializando un mapeo válido— reanuda la instrucción. Si no puede, en un sistema tipo Linux puede notificar al proceso mediante una señal como SIGSEGV o SIGBUS y terminarlo según la disposición aplicable. Una carga ordinaria no «retorna EFAULT»: no existe una interfaz de llamada que entregue ese código a la instrucción.

Debe separarse ese recorrido de otro distinto. Si una aplicación llama al kernel y entrega un puntero de usuario —por ejemplo, a una operación que copia datos—, la implementación puede detectar que el rango no es accesible y hacer que la syscall falle con EFAULT. En ese caso el código pertenece al contrato de la interfaz, no a la instrucción de carga original. La CPU produce el evento arquitectónico; el kernel decide si puede resolverlo o traducirlo al contrato de una interfaz; la aplicación sólo observa la señal o el retorno que ese contrato expone. Confundir ambos recorridos borra dónde nació cada evidencia.

El caso muestra por qué una vulnerabilidad de escalada de privilegios no es simplemente «ejecutar una instrucción de ring 0». Normalmente existe una condición que permite alterar una decisión, apuntar a un objeto equivocado, abusar de una interfaz privilegiada o aprovechar un error en una transición. La prueba profesional identifica qué frontera debía sostenerse, qué precondiciones permiten cruzarla, qué estado cambia y qué autoridad se obtiene. El nombre del bug es una síntesis, no el mecanismo.

Entradas controladas: llamadas, excepciones e interrupciones

La aplicación entrega operación y argumentos; la CPU realiza la entrada arquitectónica, pero el kernel valida referencias, tamaños, estado y autoridad antes de actuar.
La transición de la CPU habilita una entrada; el kernel todavía debe decidir si la operación está permitida.

Privilegio arquitectónico y autorización sobre un objeto son propiedades distintas.

Para que un programa de usuario pida una operación protegida existe una transición diseñada por la arquitectura y el sistema operativo. En una familia puede ser una instrucción syscall; en otra, una instrucción o mecanismo equivalente. La instrucción no concede automáticamente la operación solicitada. Transfiere el control a una entrada del kernel, cambia el contexto de ejecución conforme a reglas definidas y conserva información para retornar.

La llamada al sistema suele transportar un número de operación y argumentos en registros o memoria según una ABI (Application Binary Interface). El kernel debe validar referencias, tamaños, estados y autoridad antes de actuar. La CPU garantiza la forma de entrada y la separación de niveles; el kernel valida el contrato. Si una aplicación pasa un puntero a un búfer, el procesador no sabe si el tamaño declarado es coherente con el búfer ni si la operación corresponde al usuario correcto. Esas comprobaciones son responsabilidad del software privilegiado.

Una excepción es un evento síncrono relacionado con la instrucción que se está ejecutando: división inválida, instrucción ilegal, fallo de protección o depuración son ejemplos conceptuales. Una interrupción es una señal asíncrona, normalmente asociada con hardware o temporizadores, que permite atender un evento mientras se ejecuta otro código. La distinción temporal importa para el análisis: una excepción puede reproducirse con una instrucción y estado concretos; una interrupción depende del momento y del origen. En ambos casos, la entrada protegida debe conservar suficiente estado y regresar sin confundir la identidad de la ejecución.

El retorno tampoco es una mera vuelta al siguiente byte. El kernel debe restaurar el nivel de ejecución, la dirección de retorno y los registros definidos por la ABI; además, debe preservar invariantes sobre memoria, señales y credenciales. Un error en los datos guardados, en la validación de argumentos o en la selección del destino puede convertir una interfaz legítima en una frontera defectuosa. El uso profesional de una traza es reconstruir cada transición y preguntar qué datos fueron confiados al componente con más privilegio.

Cambio de contexto: dos significados que no deben confundirse

Un hilo es una secuencia de ejecución con PC, registros y pila propios; varios hilos de un mismo proceso suelen compartir su espacio de direcciones y otros recursos administrados por el sistema operativo. La relación concreta depende del sistema, pero proceso e hilo no son intercambiables: el proceso aporta el entorno y los recursos, mientras el hilo es la unidad que el planificador reanuda.

Cambio de modo significa que la misma ejecución cruza una frontera arquitectónica, por ejemplo de usuario a kernel durante una llamada al sistema, y luego vuelve. Cambio de contexto significa que el sistema operativo deja de ejecutar un hilo y reanuda otro, guardando y restaurando el estado necesario; si además cambia la asociación de proceso, debe cambiar también el entorno de recursos correspondiente. Pueden ocurrir juntos, pero no son sinónimos. Un kernel puede entrar y salir sin cambiar de hilo; un planificador puede cambiar de hilo como parte de una ruta de kernel. La planificación es la decisión de qué tarea ejecutar, no el simple hecho de cruzar de modo.

El estado arquitectónico que se guarda para reanudar una tarea incluye registros, PC, SP, flags y otros elementos exigidos por la arquitectura y la ABI. El sistema operativo mantiene además la asociación entre la tarea seleccionada y sus recursos: espacio de direcciones, tabla de descriptores, señales, límites y credenciales. Esas credenciales no tienen por qué copiarse dentro y fuera de la CPU en cada cambio; normalmente se alcanzan mediante las estructuras que representan la tarea o el proceso. Guardar registros no basta para identificar qué conjunto de recursos y autoridad debe acompañar a la ejecución.

Un hilo puede bloquearse en entrada/salida, ser interrumpido por un temporizador, ceder ante una llamada o migrar de núcleo; cada ruta tiene costes y requisitos distintos. «El proceso fue cambiado» es una conclusión pobre si no especifica quién ejecutaba, qué estado se guardó, qué disparó la transición y qué se restauró al volver.

El contexto guardado es un objeto de seguridad. Restaurar registros, punteros de pila, estado extendido o el espacio de direcciones que pertenecen a otra tarea puede cruzar una frontera. También debe mantenerse la asociación correcta entre la tarea y sus credenciales, aunque esas credenciales residan en estructuras del kernel y no en un registro restaurado. Los sistemas operativos deben evitar que datos de un contexto se interpreten como autoridad de otro, limpiar estados sensibles cuando corresponda y coordinar la selección de tarea con la traducción de memoria. Esto no significa que todo registro sea secreto ni que cada cambio requiera borrar toda la CPU.

Preempción y cooperación

Cambio de modo, preempción y cambio de contexto son categorías distintas: el primero puede conservar el hilo, el segundo recupera la CPU y el tercero guarda una ejecución y reanuda otra.
Cambiar de modo, recuperar la CPU y reanudar otro hilo pueden coincidir, pero no son sinónimos.

La arquitectura y el sistema operativo concretos determinan el estado que debe conservarse.

Un cambio cooperativo ocurre cuando el código cede explícitamente o realiza una operación que permite planificar otra tarea. Un cambio preemptive ocurre cuando el sistema operativo recupera el control, por ejemplo mediante una interrupción de temporizador. La preempción mejora la capacidad de compartir la CPU y limita el tiempo de una tarea, pero aumenta los puntos de interleaving. Una estructura que parece consistente en una secuencia continua puede observarse en un estado intermedio cuando otro hilo interviene.

La sincronización no se resuelve diciendo «el kernel es privilegiado». Dos hilos del mismo proceso pueden competir por un objeto; dos dispositivos pueden producir eventos en orden inesperado; un manejador de interrupción puede observar una estructura que otro código está modificando. Exclusión mutua, operaciones atómicas, barreras de memoria y protocolos de bloqueo expresan supuestos específicos. La seguridad depende de que esos supuestos cubran la transición real, incluido el caso de fallo o cancelación.

Caso conductor: una lectura de estado que debía ser imposible

Consideremos un servicio sintético con un proceso de usuario que solicita al kernel leer el estado de un dispositivo. La interfaz recibe un descriptor, un búfer y una longitud. El resultado correcto no es «el kernel lee porque tiene privilegio», sino una secuencia verificable: la entrada de sistema identifica la operación; el kernel comprueba que el descriptor pertenece al contexto y que el búfer es válido para la transferencia; una política decide si el principal tiene autoridad; el controlador accede al dispositivo; el kernel copia sólo el resultado permitido y retorna un código coherente.

Ahora aparece un fallo: la longitud se valida antes de una conversión de tipos y una ruta posterior usa una representación distinta. La CPU sigue aplicando privilegios correctamente. La llamada entra por una instrucción válida. El problema está en la lógica privilegiada que traduce un argumento no confiable en tamaño de copia. La condición puede permitir leer más bytes, pero el impacto depende de qué memoria se alcanza, qué controles existen y si la salida cruza de vuelta al usuario. La formulación profesional separa la condición, la transición, el dato observado y la autoridad obtenida.

Un control negativo ayuda a no exagerar. Con el mismo principal sintético, un descriptor que no pertenece al proceso debe ser rechazado; una longitud fuera de rango también. Si el rechazo aparece para un caso pero no para otro, la diferencia orienta la hipótesis. No hace falta reclamar ejecución arbitraria para demostrar que una validación es inconsistente. Tampoco basta con que la llamada devuelva éxito: hay que verificar el objeto leído, la cantidad transferida, los registros de auditoría y el estado del descriptor después de la operación.

Qué puede observar un profesional

Para analizar este nivel, conviene correlacionar artefactos y no tratar una sola salida como explicación completa. Un depurador puede mostrar PC, SP, registros y una instrucción en el momento de una excepción. Un volcado de kernel puede indicar el vector de entrada y la pila, pero depende de símbolos, versión y calidad del volcado. Una traza de llamadas al sistema puede mostrar una interfaz y su resultado, pero no necesariamente cada comprobación interna. Los contadores de rendimiento pueden indicar cambios de contexto, pero no atribuyen por sí solos una decisión de autorización.

Una reconstrucción mínima debería registrar arquitectura, versión del kernel, compilación relevante, hilo, modo de ejecución, evento que produjo la transición, estado visible y límites de observabilidad. Si se afirma que una instrucción «causó» un acceso, hay que distinguir correlación temporal de causalidad: la instrucción pudo preparar un argumento y una llamada posterior ejecutar la operación. Si se afirma que un cambio de contexto filtró información, hay que mostrar qué estado estaba disponible para el nuevo contexto y qué mecanismo permitió observarlo.

En respuesta a incidentes, la pregunta suele ser más acotada: ¿un proceso ejecutó código con autoridad que no debía tener? El análisis debe comparar la identidad del proceso, el nivel de privilegio, la ruta de entrada, los cambios de credenciales y la evidencia de memoria o control de flujo. Un nombre de proceso o una alerta de «kernel activity» no prueba una escalada. En ingeniería, la pregunta puede ser: ¿qué invariantes deben conservarse al cambiar de hilo? La respuesta se convierte en requisitos y pruebas: no reutilizar un descriptor fuera de su ámbito, rechazar punteros inválidos, restaurar el contexto correcto y fallar de forma controlada.

Errores frecuentes y límites del modelo

El primer error es dibujar ring 0 y ring 3 como dos cajas que explican todo aislamiento. Las arquitecturas tienen modos adicionales, extensiones, firmware, dispositivos, hypervisor y mecanismos de virtualización. Un proceso puede interactuar con una superficie privilegiada sin ejecutar directamente en el nivel más alto. La figura útil muestra qué transición y qué comprobación importan, no una jerarquía decorativa.

El segundo error es afirmar que una instrucción privilegiada es una vulnerabilidad. Que una instrucción falle en usuario es el comportamiento esperado. La vulnerabilidad aparece cuando una interfaz permite alcanzar autoridad, datos o estado fuera de la política, por una validación ausente, una confusión de contexto, una condición de carrera o una implementación incorrecta.

El tercero es llamar «cambio de contexto» a cualquier salto a kernel. Esa etiqueta borra si cambió el hilo, el proceso, el nivel, el espacio de direcciones o sólo el manejador. Cada combinación tiene riesgos y evidencia distintos.

El cuarto es asumir que el hardware valida la intención. La CPU comprueba condiciones arquitectónicas; no puede leer una política de negocio ni inferir que un identificador representa al usuario correcto. El kernel tampoco es una autoridad mágica: su código, configuración, módulos, controladores y entradas de administración deben formar parte del análisis.

Por último, el modelo no promete visibilidad total. La especulación puede dejar señales sin cambiar el estado arquitectónico; un hypervisor puede interponer otra capa; un dispositivo puede mantener estado fuera del conjunto de registros; una optimización del compilador puede cambiar la secuencia concreta. Si la conclusión depende de un detalle de microarquitectura, debe declararse la CPU, el firmware, la versión y el método de medición. No se debe extender una propiedad demostrada para una ISA a todas las arquitecturas.

Uso profesional: de la transición al argumento

Una revisión puede empezar con una tabla: evento, estado de origen, frontera cruzada, autoridad solicitada, comprobación, estado de destino, evidencia y fallo. La tabla distingue una llamada al sistema de la decisión que la sigue y un cambio de hilo de una elevación de privilegios. También ayuda a formular pruebas: una entrada válida completa la operación; una no autorizada falla sin modificar estado; una interrupción durante la transición no produce un contexto mezclado.

En threat modeling, CPU y kernel son sistemas de apoyo, no sustitutos del modelo de activos. El activo puede ser un secreto en memoria, la integridad de una política o la disponibilidad de un servicio. La amenaza puede aprovechar una interfaz privilegiada, una condición de carrera o un estado residual. La vulnerabilidad es la condición susceptible de explotación bajo precondiciones. Sólo después se estima el riesgo y se decide una mitigación: reducir superficie de entrada, validar tamaños y referencias, separar privilegios, actualizar un componente o aumentar observabilidad.

En reversing o análisis de un crash, la disciplina consiste en reconstruir una secuencia y declarar qué no se sabe. «PC estaba en el manejador de excepción» es observación. «El input produjo una escritura fuera de límites» es una inferencia que requiere conectar argumentos, tamaños y memoria. «Se obtuvo ejecución en kernel» es una conclusión más fuerte, y necesita evidencia de control de flujo y nivel, no sólo un mensaje. Esa separación evita convertir un artefacto llamativo en un hallazgo inflado.

Síntesis

Una CPU ejecuta instrucciones mediante transiciones de estado definidas por una ISA. Los niveles de privilegio y las reglas de acceso establecen barreras arquitectónicas, pero no expresan por sí solos autorización de negocio. Las llamadas al sistema, excepciones e interrupciones son entradas controladas a código con más autoridad; su seguridad depende de conservar el estado, validar argumentos y devolver el control sin mezclar contextos.

Un cambio de contexto guarda y restaura la ejecución necesaria para reanudar otro hilo o proceso. Puede coincidir con un cambio de modo, pero la diferencia importa porque identidad, memoria, credenciales y recursos no caben en una lista de registros. El análisis profesional sigue la transición concreta: qué estado existía, qué evento la produjo, qué frontera se cruzó, qué comprobación se ejecutó, qué cambió y qué evidencia permite afirmarlo.

Con ese modelo, «el procesador impidió el acceso» deja de ser una explicación completa y se convierte en una proposición acotada. Puede significar que una comprobación arquitectónica rechazó una instrucción, mientras el kernel aún debe interpretar el error y la aplicación decidir su respuesta. El capítulo siguiente añadirá memoria, direcciones, procesos y aislamiento; las distinciones de aquí serán sus premisas.

Comprobación de comprensión

  1. ISA y microarquitectura. Distingue la semántica de una ISA de su implementación microarquitectónica al analizar un fragmento de ensamblador. Respuesta modelo: la ISA fija operación y efecto arquitectónico; tuberías, cachés y predicción implementan ese contrato. El fragmento no demuestra ejecución ni impacto sin PC, modo, registros, mapeos, control de flujo y evidencia temporal. Contraejemplo: inferir que bytes presentes en memoria se ejecutaron.
  2. Rechazo privilegiado. ¿Qué comprueba la CPU cuando una aplicación ejecuta una instrucción que requiere más privilegio? Respuesta modelo: aplica las reglas de la arquitectura y produce la excepción o rechazo definido para esa ISA; el kernel recibe el evento y decide la respuesta. Eso no expresa autorización de negocio ni prueba una vulnerabilidad. Contraejemplo: llamar «escalada» a una instrucción correctamente rechazada.
  3. Syscall y autorización. Explica por qué syscall no equivale a autorización. Respuesta modelo: ofrece una entrada al kernel y transporta número y argumentos; el kernel debe validar referencias, tamaños, estado, principal y autoridad antes de modificar un objeto o devolver datos. Contraejemplo: tratar una transición arquitectónica válida como permiso para leer cualquier descriptor.
  4. Excepción e interrupción. Distingue una excepción de una interrupción y una consecuencia para la evidencia, acotando la explicación a una ISA concreta. Respuesta modelo: en las convenciones descritas por x86 y AArch64, la excepción es síncrona con la instrucción y la interrupción llega asíncronamente; los vectores, estado guardado y nombres de entradas son específicos de cada ISA. Una excepción se correlaciona con PC y operandos; una interrupción exige probar origen y orden temporal. Contraejemplo: trasladar sin declarar la semántica de un vector x86 a AArch64.
  5. Modo, contexto y planificación. ¿Por qué «entró al kernel, luego hubo un cambio de contexto» es defectuoso? Respuesta modelo: la entrada puede cambiar de modo y volver al mismo hilo; el cambio de contexto requiere que el planificador seleccione otra ejecución y se guarde/restaure su estado. Identifica hilo, proceso, disparador y estado; planificación es la selección, no el cruce de modo. Contraejemplo: usar un contador de entradas al kernel como prueba de cambio de hilo.
  6. Carga frente a syscall. Distingue una carga de usuario sobre una página no resoluble de una syscall con puntero inválido. Respuesta modelo: la carga produce una excepción arquitectónica y puede terminar en SIGSEGV/SIGBUS; la syscall puede detectar el rango durante validación/copia y devolver -EFAULT, que pertenece al contrato de la syscall, no a la instrucción de carga. Contraejemplo: atribuir EFAULT a ambos recorridos.
  7. Caso de longitud. Una interfaz recibe descriptor, búfer y longitud y una conversión permite una longitud negativa. Se devuelven bytes de otro objeto. ¿Qué separas? Respuesta modelo: condición de validación, transición, lectura observada, objeto y cantidad, principal e impacto posible; usa descriptor sintético autorizado como control positivo, uno ajeno y longitudes límite como controles negativos, y detén la prueba al confirmar la condición. Contraejemplo: ampliar datos hasta obtener una demostración más llamativa.
  8. Claim acotado. Reformula «el kernel protege todos los datos» como dos claims técnicos con precondiciones y límites. Respuesta modelo: especifica versión/arquitectura para una carga sin mapeo permitido y, por separado, una ruta que rechaza descriptor ajeno y longitud fuera de rango sin modificar estado. Contraejemplo: convertir un resultado de una configuración en una garantía para todo kernel y hardware.

Problema de transferencia

Un servicio acepta un descriptor y un búfer desde un proceso de usuario. Tras una actualización, una prueba muestra que una longitud negativa produce un error en una ruta, pero otra ruta devuelve bytes que no pertenecen al objeto solicitado. Modela la transición desde la instrucción de llamada hasta el retorno: identifica qué parte corresponde a la CPU, qué parte al kernel y qué evidencia necesitarías para afirmar una lectura fuera de ámbito. Incluye un control positivo, un control negativo y una condición de parada que evite ampliar innecesariamente la exposición.

Fuentes principales