1 puntos por GN⁺ 2024-04-28 | 1 comentarios | Compartir por WhatsApp

Resumen de IPC en Hubris

  • Hubris usa un kernel pequeño que no depende de la aplicación, y la mayor parte del código (drivers, lógica de aplicación, stack de red, etc.) existe en tareas aisladas compiladas por separado
  • Estas tareas pueden comunicarse entre sí usando un sistema de mensajería entre tareas (IPC)
  • El IPC de Hubris está compuesto por 3 operaciones fundamentales implementadas en el kernel (RECV, SEND, REPLY)
    • RECV: recoge el mensaje entrante de mayor prioridad, o bloquea hasta que llegue un mensaje
    • SEND: transfiere un mensaje y el control a la tarea receptora y suspende al llamador. El llamador pasa a estado de espera hasta recibir una respuesta
    • REPLY: entrega una respuesta a la tarea que antes usó SEND para que pueda continuar

Modos de falla nuevos e interesantes

  • Como el IPC cruza los límites entre tareas y las tareas de Hubris son programas compilados por separado, hay que tener cuidado al hacer en IPC el mismo tipo de suposiciones que el compilador hace en una llamada de función
  • Todas las tareas que actúan como servidores IPC en Hubris deben manejar errores potenciales como los siguientes:
    • recibir un mensaje con una interfaz y un código de operación inapropiados
    • recibir, en lugar del tipo de mensaje esperado, un conjunto de bytes imposible de interpretar, o un mensaje demasiado corto o demasiado largo
    • no recibir la memoria necesaria (como memoria escribible)

En programas normales y correctos estas situaciones no ocurren

  • En un programa normal de Hubris, las situaciones mencionadas arriba no ocurren
  • Las tareas quedan conectadas entre sí por la configuración del sistema de build, así que es difícil confundirlas
  • Cliente y servidor usan código Rust generado, por lo que se puede asumir que el sistema de tipos funciona a través de los límites entre tareas

El kernel no permite ninguna tontería

  • En Unix, si se violan las precondiciones de una system call, se devuelve un código de error al llamador; en Hubris, la tarea es destruida de inmediato
  • El kernel de Hubris entrega errores a las tareas que violan las reglas del kernel mediante el concepto de fallas sintéticas (Synthetic Fault)
  • En Hubris, cuando ocurre una falla de hardware o una falla sintética, la tarea se detiene inmediatamente y no puede recuperarse

El servidor tampoco permite ninguna tontería

  • Mediante la decimotercera y más extraña system call, REPLY_FAULT, el servidor puede entregar un error al cliente
  • REPLY_FAULT es similar a REPLY, pero en vez de entregar un mensaje y dejar la tarea en estado ejecutable, entrega un error y detiene la tarea
  • REPLY_FAULT permite evitar manejo innecesario de errores de IPC. Los programas normales actúan como si el problema no pudiera ocurrir, y los programas anormales ni siquiera tienen oportunidad de manejar el error
  • REPLY_FAULT ofrece una nueva forma de definir e implementar errores específicos de la aplicación, como reglas de control de acceso

Opinión de GN⁺

  • REPLY_FAULT es un mecanismo potente con el que el servidor puede provocar un panic! entre procesos en el cliente sin cooperación del lado del cliente. Gracias a esto, Hubris se vuelve un sistema muy hostil frente a programas maliciosos
  • La desventaja de REPLY_FAULT es que las pruebas de fuzzing se vuelven muy difíciles. Una tarea de ingeniería del caos que genere IPC o system calls aleatorias se reinicia de inmediato en casi cualquier comportamiento
  • Sin embargo, como las tareas normales de Hubris no generan mensajes IPC de forma dinámica, pueden funcionar sin siquiera ser conscientes de la existencia de REPLY_FAULT
  • Con REPLY_FAULT, el servidor puede hacer que al cliente le ocurra un error de forma arbitraria, pero la evaluación de esto todavía no está completamente cerrada
  • El manejo agresivo de errores de Hubris ayuda a detectar errores en etapas tempranas del desarrollo y, a diferencia de los códigos de error, hace imposible ignorarlos
  • Usar una forma universal de manejar errores de IPC puede introducir sobrecarga innecesaria incluso en programas normales. REPLY_FAULT parece una solución elegante que evita eso y al mismo tiempo responde con dureza ante programas anormales

1 comentarios

 
GN⁺ 2024-04-28
Opinión de Hacker News

En resumen, se plantea lo siguiente:

  • Se expresa preocupación sobre si REPLY_FAULT se propaga en cadena y sobre las vulnerabilidades que eso podría causar

    • En una situación donde A espera a B y B espera a C, hace falta confirmar si, cuando C hace REPLY_FAULT, A también termina junto con los demás
    • Si ese fuera el caso, todo el sistema podría volverse vulnerable
    • Si SEND tiene una estructura cíclica, incluso podría terminar matándose a sí mismo sin querer
  • REPLY_FAULT ofrece una forma de definir e implementar errores específicos de la aplicación, como el control de acceso

    • Esto resulta útil cuando el sistema es pequeño y estrechamente integrado, y en su mayoría el diseñador del sistema también escribe la aplicación
    • Sin embargo, al integrarse con código de terceros, preocupa que la contraparte pueda terminar el proceso inmediatamente en cualquier momento
    • En el mundo existen muchos drivers y procesos en segundo plano de mala calidad escritos por desarrolladores presionados por sus administradores
  • En sistemas donde un solo equipo escribe todo el código, eliminar clientes sospechosos puede acelerar la velocidad de iteración

  • Hubris puede verse como un kernel que permite que el servidor realice efectos que el cliente no puede manejar

    • Esto dificulta la reutilización y composición del código, pero simplifica el modelo de ejecución
    • En sistemas embebidos estáticos, podría ser el compromiso correcto
  • Hubris y Humility son tecnologías en las que uno querría profundizar, pero es difícil por las limitaciones de tiempo y obligaciones

  • En un RFC del Día de los Inocentes sobre HTTP, se propone el código de estado HTTP 499 con el significado de "deberías avergonzarte"

    • Encaja en un contexto como "qué demonios... pero en realidad está bien"
  • Citando la frase de Einstein, "tan simple como sea posible, pero no más simple", se señala que el diseño de Hubris viola esta última parte

    • No hay interés en entornos operativos que no permitan en absoluto el desorden del mundo real
  • Humility es un nombre excelente para un depurador

    • Muchos programadores se niegan a usar un depurador porque asumen que el código "bueno" no necesita depuración
  • En Linux, no es posible terminar directamente otros programas solo con sockets, pero con privilegios de root sí se puede matar otros procesos o incluso reiniciar el sistema

    • En contenedores, los privilegios de root son comunes, así que este riesgo existe
  • Esto entra un poco en conflicto con la sabiduría tradicional de los sistemas de red: "sé liberal al aceptar y estricto al emitir"

    • Sin embargo, al cambiar una API y mantener la compatibilidad con programas existentes, no queda otra que ser liberal al aceptar