Zenbleed: como a busca pelo desempenho da CPU pode colocar suas senhas em risco

Zenbleed: como a busca pelo desempenho da CPU pode colocar suas senhas em risco

Zenbleed: Como a busca pelo desempenho da CPU pode colocar suas senhas em risco PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

Lembra do Heartbleed?

Esse foi o bug, em 2014, que introduziu o sufixo -sangrar para vulnerabilidades que vazar dados de forma aleatória maneira que nem o atacante nem a vítima podem controlar de forma confiável.

Em outras palavras, um bandido não pode usar um bug estilo bleed para um ataque de precisão, como “Encontre o arquivo de senha shadow no /etc diretório e faça o upload para mim” ou “Pesquise para trás na memória até a primeira execução de 16 dígitos ASCII consecutivos; é um número de cartão de crédito, então guarde para mais tarde.

No Heartbleed, por exemplo, você poderia enganar um servidor sem patch para enviar uma mensagem que deveria ter no máximo 16 bytes, mas que incluía erroneamente cerca de 64,000 bytes adicionais anexados no final.

Você não podia escolher o que havia naqueles 64,000 bytes saqueados; você acabou de receber o que quer que esteja adjacente na memória à mensagem genuína que deveria receber.

Às vezes, você obtinha pedaços de todos os zeros ou dados criptografados desconhecidos para os quais você não tinha a chave de descriptografia…

…mas de vez em quando você obtém fragmentos de texto não criptografado de uma página da web que o visitante anterior baixou, ou partes de um e-mail que outra pessoa acabou de enviar, ou até mesmo blocos de memória com as próprias chaves criptográficas privadas do servidor.

Agulhas abundantes em palheiros sem fim

Os invasores normalmente exploram bugs baseados em sangramento simplesmente acionando-os repetidas vezes automaticamente, coletando uma pilha gigante de dados não autorizados e, em seguida, vasculhando-os mais tarde, à vontade.

Agulhas são surpreendentemente fáceis de extrair de palheiros se (a) você puder automatizar a busca usando um software para fazer o trabalho duro para você, (b) você não precisar de respostas imediatamente e (c) você tiver muitas e muitos palheiros, então você pode perder muitas ou mesmo a maioria das agulhas e ainda acabar com um estoque considerável.

Outros bugs com nomes sangrentos incluem divagado, que provocou deliberadamente erros temporários de memória para adivinhar o que estava armazenado nas partes próximas de um chip de RAM e Sangramento de opções, onde você pode perguntar repetidamente a um servidor da Web quais opções de HTTP ele suporta, até que ele envie uma resposta com os dados de outra pessoa por engano.

Em analogia, um bug estilo bleed é um pouco como uma loteria discreta que não tem nenhum prêmio de mega-jackpot garantido, mas onde você tem uma chance sorrateira de comprar 1,000,000 de bilhetes pelo preço de um.

Bem, o famoso caçador de bugs do Google, Tavis Ormandy, acaba de relatou um novo bug deste tipo que ele é apelidado Sangramento Zen, porque o bug se aplica ao mais recente da AMD Zen 2 gama de processadores de alto desempenho.

Infelizmente, você pode explorar o bug de quase qualquer processo ou thread em um computador e eliminar dados pseudo-aleatoriamente de quase qualquer lugar na memória.

Por exemplo, um programa executado como um usuário sem privilégios dentro de uma máquina virtual (VM) convidada que deveria estar isolada do restante do sistema pode acabar com dados de outros usuários na mesma VM ou de outras VMs na mesma computador, ou do programa host que deveria estar controlando as VMs, ou mesmo do kernel do próprio sistema operacional host.

Ormandy foi capaz de crio código de prova de conceito que vazou cerca de 30,000 bytes de dados de outras pessoas por segundo por núcleo do processador, 16 bytes por vez.

Isso pode não parecer muito, mas 30 KB/s é suficiente para expor incríveis 3 GB ao longo de um dia, com dados que são acessados ​​com mais regularidade (incluindo senhas, tokens de autenticação e outros dados que deveriam ser mantidos em segredo) possivelmente aparecendo repetidamente.

E com os dados expostos em pedaços de 16 bytes, é provável que os invasores encontrem muitos fragmentos reconhecíveis nas informações capturadas, ajudando-os a filtrar e classificar os palheiros e focar nas agulhas.

O preço do desempenho

Não vamos tentar explicar a falha do Zenbleed aqui (por favor, veja Tavis Ormandy's artigo próprio para obter detalhes), mas vamos nos concentrar no motivo pelo qual o bug apareceu em primeiro lugar.

Como você provavelmente adivinhou, visto que já mencionamos processos, threads, núcleos e gerenciamento de memória, esse bug é um efeito colateral dos “recursos” internos que os processadores modernos incluem para melhorar o desempenho o máximo possível. , incluindo um truque legal, mas propenso a bugs, conhecido no mercado como execução especulativa.

Falando vagamente, a ideia por trás da execução especulativa é que, se um núcleo de processador estiver ocioso, talvez esperando para descobrir se deve cair no THEN ou de ELSE caminho de uma decisão if-then-else em seu programa, ou esperando por uma verificação de controle de acesso de hardware para determinar se é realmente permitido usar o valor de dados armazenado em um endereço de memória específico ou não…

… então vale a pena continuar de qualquer maneira e calcular com antecedência (essa é a parte da “execução especulativa”) caso a resposta seja útil.

Se a resposta especulativa se revelar desnecessária (porque deu certo THEN resultado quando o código desceu o ELSE path em vez disso) ou acabar fora dos limites do processo atual (no caso de falha na verificação de acesso), ele pode simplesmente ser descartado.

Você pode pensar na execução especulativa como um apresentador de um programa de perguntas e respostas que espia a resposta na parte inferior do cartão enquanto faz a pergunta atual, presumindo que o competidor tentará responder e precisará consultar a resposta diretamente ausente.

Mas em alguns programas de perguntas e respostas, o competidor pode dizer “Passa”, pulando a pergunta para voltar a ela mais tarde.

Se isso acontecer, o anfitrião precisa colocar a resposta não utilizada fora de sua mente e seguir em frente com a próxima pergunta, e a próxima, e assim por diante.

Mas se a pergunta “aprovada” aparecer novamente, quanto o fato de que eles agora sabem a resposta com antecedência afetará como eles a perguntam pela segunda vez?

E se eles inadvertidamente lerem a pergunta de maneira diferente ou usarem um tom de voz diferente que possa dar ao competidor uma dica involuntária?

Afinal, a única maneira verdadeira de “esquecer” algo completamente é nunca tê-lo conhecido em primeiro lugar.

O problema com vetores

No bug Zenbleed de Ormandy, agora oficialmente conhecido como CVE-2023-20593, o problema surge quando um processador AMD Zen 2 executa uma instrução especial que existe para definir vários chamados registros de vetores para zero ao mesmo tempo.

Os registradores vetoriais são usados ​​para armazenar dados usados ​​por instruções numéricas e de processamento de dados especiais de alto desempenho e, na maioria dos processadores Intel e AMD modernos, eles têm 256 bits de largura, ao contrário dos 64 bits dos registradores de uso geral da CPU usados ​​para fins de programação tradicionais. .

Esses registradores de vetores especiais podem ser operados em 256 bits (32 bytes) por vez ou apenas 128 bits (16 bytes) por vez.

Na verdade, por razões históricas, as CPUs de hoje têm dois conjuntos completamente diferentes de instruções de código de máquina no estilo vetorial: um grupo mais novo conhecido como AVX (extensões vetoriais avançadas), que pode funcionar com 128 ou 256 bits, e um grupo de instruções mais antigo e menos poderoso chamado SSE (extensões SIMD de streaming, onde SIMD por sua vez significa dados de instrução única/múltiplos), que só pode funcionar com 128 bits por vez.

Irritantemente, se você executar algum código AVX de estilo novo, depois algum código SSE de estilo antigo e depois mais algum código AVX, as instruções SSE no meio bagunçam os 128 bits superiores dos novos registros AVX de 256 bits, mesmo que as instruções SSE estejam, pelo menos no papel, fazendo seus cálculos apenas nos 128 bits inferiores.

Portanto, o processador salva silenciosamente os 128 bits superiores dos registros AVX antes de alternar para o modo SSE compatível com versões anteriores e, em seguida, restaura esses valores salvos na próxima vez que você começar a usar as instruções AVX, evitando assim quaisquer efeitos colaterais inesperados da mistura de código vetorial antigo e novo .

Mas esse processo de salvar e restaurar prejudica o desempenho, o que tanto Intel e AMD os guias de programação o alertam fortemente.

AMD diz:

Há uma penalidade significativa por misturar instruções SSE e AVX quando os 128 bits superiores dos registros YMM [256 bits de largura] contêm dados diferentes de zero.

A transição em qualquer direção fará com que uma microfalha se espalhe ou preencha os 128 bits superiores de todos os dezesseis registradores YMM.

Haverá uma penalidade de aproximadamente 100 ciclos para sinalizar e lidar com esta falha.

E a Intel diz algo semelhante:

O hardware salva o conteúdo dos 128 bits superiores dos registros YMM [256 bits] ao fazer a transição de AVX para SSE e, em seguida, restaura esses valores ao fazer a transição de volta [...]

As operações de salvar e restaurar causam uma penalidade que chega a várias dezenas de ciclos de clock para cada operação.

Para salvar o dia, existe uma instrução vetorial especial chamada VZEROUPPER que zera os 128 bits superiores de cada registrador vetorial de uma só vez.

Chamando VZEROUPPER, mesmo que seu próprio código realmente não precise dele, você sinaliza ao processador que não se importa mais com os 128 bits superiores desses registradores de 256 bits, portanto, eles não precisam ser salvos se uma instrução SSE da velha escola vier junto a seguir.

Isso ajuda a acelerar o seu código ou, pelo menos, impede que você diminua a velocidade de qualquer outra pessoa.

E se isso soa como um kludge…

… bem, é.

É um hack no nível do processador, se preferir, apenas para garantir que você não reduza o desempenho tentando melhorá-lo.

Onde entra o CVE-2023-20593?

Toda essa fixação no desempenho levou Ormandy ao seu buraco de vazamento de dados do Zenbleed, porque:

  • O código AVX é extremamente comumente usado para fins não matemáticos, como trabalhar com texto. Por exemplo, a popular biblioteca de programação Linux glibc usa instruções e registros AVX para acelerar a função strlen() que é usado para encontrar o comprimento de strings de texto em C. (Falando livremente, strlen() usar o código AVX permite pesquisar 16 bytes de uma string por vez, procurando o byte zero que denota onde termina, em vez de usar um loop convencional que verifica byte por byte.)
  • Os processadores Zen 2 da AMD não desfazem de forma confiável VZEROUPPER quando um caminho de código de execução especulativa falha. Ao “zerar” os 128 bits superiores de um registrador de 256 vetores porque o processador adivinhou errado e o VZEROUPPER operação precisa ser revertida, o registrador às vezes acaba com 128 bits (16 bytes) “restaurados” do código AVX de outra pessoa, em vez dos dados que realmente estavam lá antes.

Na vida real, parece que os programadores raramente usam VZEROUPPER de maneiras que precisam ser revertidas, ou então esse bug pode ter sido encontrado anos atrás, talvez até mesmo durante o desenvolvimento e teste na própria AMD.

Mas, experimentando cuidadosamente, Ormandy descobriu como criar loops de código AVX que não apenas acionavam repetidamente a execução especulativa de um VZEROUPPER instrução, mas também forçou regularmente essa instrução a ser revertida e os registros AVX “deszerados”.

Infelizmente, muitos outros programas convencionais usam muito as instruções AVX, mesmo que não sejam o tipo de aplicativo, como jogos, ferramentas de renderização de imagem, crackers de senha ou criptomineradores, que você esperaria precisar de um código de estilo vetorial de alta velocidade.

Seu sistema operacional, cliente de e-mail, navegador da web, servidor da web, editor de código-fonte, janela de terminal – praticamente todos os programas que você usa rotineiramente – quase certamente usa seu quinhão de código AVX para melhorar o desempenho.

Assim, mesmo em condições muito típicas, Ormandy às vezes acabava com os restos fantasmagóricos dos dados de outros programas misturados em seus próprios dados AVX, que ele podia detectar e rastrear.

Afinal, se você sabe o que deve estar nos registradores AVX após um VZEROUPPER operação é revertida, é fácil identificar quando os valores nesses registradores dão errado.

Nas próprias palavras de Ormandy:

[B]asic operações como strlen(), memcpy() e strcmp() [encontrar o tamanho da cadeia de texto, copiar a memória, comparar cadeias de texto] usará os registradores vetoriais - para que possamos espionar com eficácia as operações que ocorrem em qualquer lugar do sistema!

Não importa se eles estão acontecendo em outras máquinas virtuais, sandboxes, contêineres, processos, o que quer que seja.

Como mencionamos anteriormente, se você tiver um pool diário de 3 GB de dados fantasmas não estruturados e pseudo-aleatoriamente selecionados por núcleo de CPU, talvez não ganhe o equivalente na loteria a um jackpot multimilionário.

Mas é quase certo que você ganhará o equivalente a milhares de prêmios de US$ 1000, sem correr o risco de enfiar o nariz nos processos e páginas de memória de outras pessoas, como o malware tradicional de “escudo RAM” precisa fazer.

O que fazer?

CVE-2023-20593 foi divulgado com responsabilidade e a AMD já produziu um patch de microcódigo para atenuar a falha.

Se você possui uma CPU da família Zen 2 e está preocupado com esse bug, fale com o fornecedor da placa-mãe para obter mais informações sobre como obter e aplicar as correções relevantes.

Em sistemas operacionais com ferramentas de software que suportam ajustes nos chamados MSRs (registros específicos do modelo) em seu processador que controla sua configuração de baixo nível, há um sinalizador não documentado (bit 9) que você pode definir em um registro de modelo mal documentado (MSR 0xC0011029) que aparentemente desativa o comportamento que causa o bug.

MSR 0xC0011029 é referido na lista de discussão do kernel do Linux arquivo como o DE_CFG registrar, aparentemente abreviação de decodificar configuração, e outros bits bem conhecidos neste registro são usados ​​para regular outros aspectos da execução especulativa.

Portanto, estamos supondo que DE_CFG[9], que é uma abreviação de “bit 9 de MSR 0xC0011029”, decide se permite instruções com efeitos colaterais complexos, como VZEROUPPER para ser experimentado especulativamente em tudo.

Obviamente, se você nunca permitir que o processador zere os registradores vetoriais, a menos que você já tenha certeza de que nunca precisará “deszerar” esses registradores e reverter as alterações, esse bug nunca poderá ser acionado.

O fato desse bug não ter sido detectado até agora sugere que a execução especulativa do mundo real de VZEROUPPER não acontece com muita frequência e, portanto, é improvável que esse hack/correção de baixo nível tenha um impacto perceptível no desempenho.

O artigo de Ormandy inclui uma descrição de como reconfigurar o bit MSR relevante em seu processador Zen 2 no Linux e FreeBSD.

(Você verá DE_CFG[9] descrito como pedaço de frango, jargão para uma definição de configuração que você ativa on virar WOW! um recurso do qual você tem medo.)

OpenBSD, ouvimos, estará forçando DE_CFG[9] liga automaticamente em todos os processadores Zen 2, suprimindo assim esse bug por padrão em busca de segurança em detrimento do desempenho; sobre Linux e outros BSDs, você pode fazer isso com ferramentas de linha de comando (raiz necessária), como wrmsr e cpucontrol.

Mac os usuários podem relaxar porque todos os Macs não ARM têm chips Intel, até onde sabemos, em vez dos AMD, e os processadores Intel não são conhecidos por serem vulneráveis ​​a esse bug específico.

Windows os usuários podem precisar recorrer a hacks de driver de kernel não oficiais (evite-os, a menos que você realmente saiba o que está fazendo, devido aos riscos de segurança de inicializar no modo "permitir qualquer driver antigo") ou instalar o depurador WinDbg oficial, habilite a depuração do kernel local e use um script WinDbg para ajustar o MSR relevante.

(Admitimos que não tentamos nenhuma dessas mitigações, porque não temos um computador baseado em AMD disponível no momento; informe-nos como você se sairá se o fizer!)


Carimbo de hora:

Mais de Segurança nua