1 pontos por GN⁺ 2024-04-28 | 1 comentários | Compartilhar no WhatsApp

Visão geral do IPC do Hubris

  • O Hubris usa um kernel pequeno e não dependente da aplicação, e a maior parte do código (drivers, lógica da aplicação, stack de rede etc.) existe em tarefas isoladas compiladas separadamente
  • Essas tarefas podem se comunicar entre si usando um sistema de mensagens entre tarefas (IPC)
  • O IPC do Hubris é composto por 3 operações centrais implementadas no kernel (RECV, SEND, REPLY)
    • RECV: coleta a mensagem de maior prioridade recebida ou bloqueia até que uma mensagem chegue
    • SEND: envia a mensagem e o controle para a tarefa receptora e suspende o chamador. O chamador entra em estado de espera até receber uma resposta
    • REPLY: entrega uma resposta à tarefa que anteriormente usou SEND, permitindo que ela continue

Modos de falha novos e interessantes

  • Como o IPC atravessa os limites entre tarefas e as tarefas do Hubris são programas compilados separadamente, é preciso ter cuidado ao fazer no IPC suposições equivalentes às que o compilador faz em chamadas de função
  • Toda tarefa que atua como servidor IPC no Hubris precisa lidar com os seguintes erros potenciais:
    • receber uma mensagem com a interface e o código de operação incorretos
    • receber um conjunto de bytes impossível de interpretar no lugar do tipo de mensagem esperado, ou uma mensagem curta ou longa demais
    • não receber a memória necessária (como memória gravável)

Em programas normais e corretos, essas situações não acontecem

  • Em um programa Hubris normal, as situações mencionadas acima não acontecem
  • As tarefas são conectadas entre si pela configuração do sistema de build, então é difícil confundi-las
  • Cliente e servidor usam código Rust gerado, então é possível assumir que o sistema de tipos funciona além dos limites entre tarefas

O kernel não permite nenhum absurdo

  • No Unix, violar as precondições de uma system call faz com que um código de erro seja retornado ao chamador, mas no Hubris a tarefa é destruída imediatamente
  • O kernel do Hubris entrega erros a tarefas que violam as regras do kernel por meio do conceito de Falha Sintética (Synthetic Fault)
  • No Hubris, quando ocorre uma falha de hardware ou sintética, a tarefa é interrompida imediatamente e não pode ser recuperada

O servidor também não permite nenhum absurdo

  • Por meio da 13ª e mais incomum system call, REPLY_FAULT, o servidor pode entregar um erro ao cliente
  • REPLY_FAULT é semelhante a REPLY, mas em vez de entregar uma mensagem e tornar a tarefa executável, entrega um erro e interrompe a tarefa
  • Com REPLY_FAULT, é possível evitar tratamento desnecessário de erros de IPC. Programas normais se comportam como se problemas não pudessem acontecer, e programas anormais nem chegam a ter a chance de tratar o erro
  • REPLY_FAULT oferece uma nova forma de definir e implementar erros específicos da aplicação, como regras de controle de acesso

Opinião do GN⁺

  • REPLY_FAULT é um mecanismo poderoso que permite ao servidor disparar um panic! entre processos no cliente sem cooperação do lado do cliente. Com isso, o Hubris se torna um sistema muito hostil a programas maliciosos
  • A desvantagem de REPLY_FAULT é que testes de fuzzing ficam muito difíceis. Uma tarefa de engenharia do caos que gere IPCs ou system calls aleatórios é resetada imediatamente em quase qualquer operação
  • No entanto, como tarefas Hubris normais não geram mensagens IPC dinamicamente, elas podem funcionar sem sequer perceber a existência de REPLY_FAULT
  • Com REPLY_FAULT, o servidor pode provocar falhas aleatórias no cliente, mas a avaliação disso ainda não foi totalmente concluída
  • O tratamento agressivo de erros do Hubris ajuda a encontrar erros no início do desenvolvimento e, ao contrário de códigos de erro, torna impossível ignorá-los
  • Usar uma forma universal de tratar erros de IPC pode introduzir overhead desnecessário até em programas normais. REPLY_FAULT parece ser uma solução elegante para evitar isso, ao mesmo tempo em que responde com rigor a programas anormais

1 comentários

 
GN⁺ 2024-04-28
Comentários do Hacker News

Em resumo, os pontos são os seguintes:

  • Foi levantada a preocupação sobre se REPLY_FAULT se propaga em cadeia e sobre as vulnerabilidades decorrentes disso

    • Na situação em que A espera por B, e B espera por C, é preciso verificar se, quando C faz REPLY_FAULT, A também é encerrado
    • Se for assim, o sistema inteiro pode se tornar vulnerável
    • Se SEND formar uma estrutura cíclica, pode até acabar encerrando a si mesmo sem querer
  • REPLY_FAULT oferece uma forma de definir e implementar erros específicos da aplicação, como controle de acesso

    • Isso é útil quando o sistema é pequeno e coeso, e na maior parte dos casos o projetista do sistema também escreve a aplicação
    • Porém, ao integrar com código de terceiros, surge a preocupação de que o outro lado possa encerrar o processo imediatamente a qualquer momento
    • Existem muitos drivers e processos em segundo plano ruins por aí, escritos por desenvolvedores pressionados por administradores
  • Em sistemas em que uma única equipe escreve todo o código, eliminar clientes suspeitos pode acelerar a velocidade de iteração

  • O Hubris pode ser visto como um kernel que permite que o servidor execute efeitos que o cliente não consegue tratar

    • Isso dificulta o reúso e a composição de código, mas simplifica o modelo de execução
    • Em sistemas embarcados estáticos, isso pode ser o compromisso certo
  • Hubris e Humility são tecnologias nas quais seria interessante mergulhar a fundo, mas isso é difícil por limitações de tempo e obrigações

  • Em uma RFC de 1º de abril sobre HTTP, foi proposto o código de status HTTP 499 com o significado de "você deveria sentir vergonha"

    • Isso combina com um contexto do tipo "ué... mas na verdade até que faz sentido"
  • Citando a frase de Einstein, "tão simples quanto possível, mas não mais simples que isso", foi apontado que o projeto do Hubris viola a segunda parte

    • Não há interesse em ambientes operacionais que não toleram absolutamente nenhuma desordem do mundo real
  • Humility é um excelente nome para um depurador

    • Muitos programadores se recusam a usar depuradores por presumirem que código "bom" não precisa de depuração
  • No Linux, não é possível encerrar diretamente outro programa apenas com sockets, mas com privilégios de root é possível matar outros processos ou até reiniciar a máquina

    • Em contêineres, privilégios de root são comuns, então esse risco existe
  • Isso entra um pouco em conflito com a sabedoria tradicional dos sistemas de rede de "seja liberal no que aceita e rigoroso no que envia"

    • Porém, ao mudar uma API e manter a compatibilidade com programas existentes, acaba sendo inevitável ser liberal no que se aceita