fusão e espectro, explicou
embora hoje em dia eu seja conhecido principalmente por redes de nível de aplicação e sistemas distribuídos, eu passei a primeira parte da minha carreira trabalhando em sistemas operacionais e hipervisores. Eu mantenho um fascínio profundo com os detalhes de baixo nível de como processadores modernos e sistemas de software funcionam. Quando o recente colapso e vulnerabilidades Spectre foram anunciados, eu pesquisei as informações disponíveis e Estava ansioso para saber mais.as vulnerabilidades são surpreendentes.; Eu diria que eles são uma das descobertas mais importantes na ciência da computação nos últimos 10-20 anos. As mitigações também são difíceis de entender e informações precisas sobre eles é difícil de encontrar. Isto não é surpreendente, dada a sua natureza crítica. Mitigar as vulnerabilidades requer meses de trabalho secreto de todos os principais fornecedores de CPU, sistema operacional e nuvem. O fato de que as questões foram mantidas em segredo por 6 meses, quando literalmente centenas de pessoas estavam provavelmente trabalhando nelas é incrível.
embora muito tenha sido escrito sobre fusão e espectro desde o seu anúncio, Eu não vi uma boa introdução de nível médio para as vulnerabilidades e mitigações. Neste post eu vou tentar corrigir isso, fornecendo uma introdução suave ao hardware e software de fundo necessário para entender as vulnerabilidades, uma discussão sobre as próprias vulnerabilidades, bem como uma discussão sobre as mitigações atuais.
Nota importante: porque eu não tenho trabalhado diretamente nas mitigações, e não trabalhar na Intel, Microsoft, Google, Amazon, Red Hat, etc. alguns dos pormenores que vou fornecer podem não ser inteiramente exactos. Eu juntei este post com base em meu conhecimento de como esses sistemas funcionam, documentação publicamente disponível, e patches/discussão postados para LKML e xen-devel. Eu adoraria ser corrigido se qualquer um deste post é impreciso, embora eu duvido que vai acontecer a qualquer momento em breve dado o quanto deste assunto ainda é coberto pela NDA.
nesta secção I irá fornecer alguns antecedentes necessários para compreender as vulnerabilidades. A seção encobre uma grande quantidade de detalhes e destina-se aos leitores com uma compreensão limitada de hardware e software de sistemas de computador.
memória Virtual
memória Virtual é uma técnica usada por todos os sistemas operacionais, desde a década de 1970. Ele fornece uma camada de abstração entre o endereço de memória de layout que mais se vê software e dispositivos físicos de apoio que a memória (memória RAM, discos, etc.). Em um alto nível, ele permite que as aplicações utilizem mais memória do que a máquina realmente tem; isso fornece uma poderosa abstração que torna muitas tarefas de programação mais fáceis.
a Figura 1 mostra uma simplista computador com 400 bytes de memória estabelecidos em “páginas” de 100 bytes (real de uso de computadores potências de dois, normalmente 4096). O computador tem dois processos, cada um com 200 bytes de memória em 2 páginas cada. Os processos podem estar rodando o mesmo código usando endereços fixos na faixa de 0-199 byte, no entanto eles são apoiados por memória física discreta de tal forma que eles não influenciam uns aos outros. Embora os modernos sistemas operacionais e computadores usem memória virtual de uma forma substancialmente mais complicada do que o que é apresentado neste exemplo, a premissa básica apresentada acima vale em todos os casos. Os sistemas operacionais estão abstraindo os endereços que a aplicação vê a partir dos recursos físicos que os apoiam.
traduzir endereços virtuais para endereços físicos é uma operação tão comum em computadores modernos que se o SO tivesse que estar envolvido em todos os casos, o computador seria incrivelmente lento. O hardware de CPU moderno fornece um dispositivo chamado “Translation Lookaside Buffer” (TLB) que caches usaram mapeamentos recentemente. Isso permite que as CPUs executem a tradução de endereço diretamente em hardware na maioria das vezes.
Figura 2 mostra o fluxo de tradução de endereço:
- um programa obtém um endereço virtual.
- A CPU tenta traduzi-la usando o TLB. Se o endereço for encontrado, a tradução é usada.
- Se o endereço não for encontrado, a CPU consulta um conjunto de “tabelas de páginas” para determinar o mapeamento. Tabelas de páginas são um conjunto de páginas de memória física fornecidas pelo sistema operacional em um local que o hardware pode encontrá-los (por exemplo, o registro CR3 no hardware x86). Tabelas de páginas mapeiam endereços virtuais para endereços físicos, e também contêm metadados, como permissões.
- Se a tabela de páginas contém um mapeamento ele é devolvido, em cache no TLB, e usado para pesquisa. Se a tabela de páginas não contém um mapeamento, uma “falha de página” é elevada para o SO. Uma falha de página é um tipo especial de interrupção que permite ao so assumir o controle e determinar o que fazer quando há um mapeamento em falta ou inválido. Por exemplo, o SO pode terminar o programa. Ele também pode alocar alguma memória física e mapeá-lo no processo. Se um manipulador de falhas de página continuar a execução, o novo mapeamento será usado pelo TLB.
a Figura 3 mostra um pouco mais a visão realista de que a memória virtual parece em um computador moderno (pré-Crise — mais sobre isso abaixo). Nesta configuração temos as seguintes características:
- a memória do Kernel é mostrada a vermelho. Está contido no intervalo de endereços físicos 0-99. Memória do Kernel é uma memória especial que apenas o sistema operacional deve ser capaz de acessar. Os programas de usuário não devem ser capazes de acessá-lo.
- a memória do Utilizador é mostrada em cinzento.a memória física não afetada é mostrada em azul.
neste exemplo, começamos a ver algumas das características úteis da memória virtual. Principalmente:
- a memória do usuário em cada processo está no intervalo virtual 0-99, mas apoiada por diferentes memórias físicas.
- memória Kernel em cada processo está no intervalo virtual 100-199, mas apoiada pela mesma memória física.
Como mencionei brevemente na secção anterior, cada página tem bits de permissão associados. Mesmo que a memória do kernel seja mapeada em cada processo de usuário, quando o processo está rodando no modo de usuário, ele não pode acessar a memória do kernel. Se um processo tentar fazê-lo, ele irá desencadear uma falha de página em que ponto o sistema operacional irá terminá-lo. No entanto, quando o processo está rodando no modo kernel (por exemplo, durante uma chamada de sistema), o processador permitirá o acesso.
neste ponto vou note que este tipo de dupla (mapeamento de cada processo de ter o kernel mapeada diretamente) tem sido uma prática comum no design de sistema operacional por mais de trinta anos, por motivos de desempenho (chamadas de sistema são muito comuns e que levaria muito tempo para remapear o kernel ou em espaço de usuário em cada transição).
cache da CPU topologia
a próxima informação de fundo necessária para compreender as vulnerabilidades é a topologia de CPU e cache dos processadores modernos. A figura 4 mostra uma topologia genérica que é comum à maioria dos CPUs modernos. Ele é composto pelos seguintes componentes:
- a unidade básica de execução é o “thread CPU” ou “thread hardware” ou “hyper-thread”.”Cada thread CPU contém um conjunto de registradores e a capacidade de executar um fluxo de código de máquina, muito como um thread de software.
- CPU threads estão contidos dentro de um ” núcleo de CPU.”A maioria dos CPUs modernos contêm dois fios por núcleo.os CPUs modernos geralmente contêm vários níveis de memória de cache. Os níveis de cache mais próximos da linha de CPU são menores, mais rápidos e mais caros. Quanto mais longe da CPU e mais perto da memória principal, o cache é maior, mais lento e menos caro.
- O design moderno típico da CPU usa um cache L1 / L2 por núcleo. Isto significa que cada thread CPU no núcleo faz uso dos mesmos caches.
- múltiplos núcleos de CPU estão contidos em um ” pacote de CPU. Os CPUs modernos podem conter mais de 30 núcleos (60 threads) ou mais por pacote.
- todos os núcleos de CPU no pacote normalmente compartilham um cache L3.
- pacotes CPU se encaixam em ” sockets.”A maioria dos computadores de consumo são socket único, enquanto muitos servidores de datacenter têm vários sockets.
Especulativa de execução
a última peça de informação de fundo necessária para entender as vulnerabilidades é uma técnica de CPU moderna conhecida como ” execução especulativa. A figura 5 mostra um diagrama genérico do motor de execução dentro de uma CPU moderna.
O takeaway primário é que os CPUs modernos são incrivelmente complicados e não simplesmente executar as instruções da máquina em ordem. Cada linha de CPU tem um complicado motor de tubulação que é capaz de executar instruções fora de ordem. A razão para isso tem a ver com caching. Como eu discuti na seção anterior, cada CPU faz uso de vários níveis de cache. Cada falha de cache adiciona uma quantidade substancial de tempo de atraso para a execução do programa. Para mitigar isso, os processadores são capazes de executar antecipadamente e fora de ordem enquanto esperam por cargas de memória. Isto é conhecido como execução especulativa. O seguinte excerto de código demonstra isso.
if (x < array1_size) {
y = array2 * 256];
}
No trecho de código anterior, imagine que array1_size
não está disponível no cache, mas o endereço de array1
é. A CPU pode adivinhar (especular) que x
é inferior a array1_size
e efectuar os cálculos dentro da declaração if. Uma vez quearray1_size
é lido a partir da memória, a CPU pode determinar se adivinhou corretamente. Se o fez, pode continuar a ter poupado muito tempo. Se não o fez, pode deitar fora os cálculos especulativos e começar de novo. Isto não é pior do que se tivesse esperado.outro tipo de execução especulativa é conhecido como previsão indireta do ramo. Isto é extremamente comum em programas modernos devido ao dispatch virtual.
class Base {
public:
virtual void Foo() = 0;
};class Derived : public Base {
public:
void Foo() override { … }
};Base* obj = new Derived;
obj->Foo();
(A origem do trecho de código anterior é este post)
O caminho do trecho de código anterior é implementado em código de máquina é para carregar a “tabela v” ou “virtual” e “tabela de distribuição” a partir da localização de memória que obj
pontos a e, em seguida, chamá-lo. Como esta operação é tão comum, os CPUs modernos têm vários caches internos e muitas vezes adivinharão (especular) onde o ramo indireto irá e continuará a execução nesse ponto. Mais uma vez, se o CPU adivinhar corretamente, ele pode continuar tendo poupado um monte de tempo. Se não o fez, pode deitar fora os cálculos especulativos e começar de novo.
vulnerabilidade de fusão
tendo agora coberto toda a informação de fundo, podemos mergulhar nas vulnerabilidades.
Rogue data cache load
a primeira vulnerabilidade, conhecida como fusão, é surpreendentemente simples de explicar e quase trivial de explorar. O código exploit parece-se com o seguinte::
vamos dar cada passo acima, descrever o que ele faz, e como ele leva a ser capaz de ler a memória de todo o computador a partir de um programa de usuário.
- na primeira linha, é atribuída uma “matriz de sonda”. Esta é a memória em nosso processo que é usado como um canal lateral para recuperar dados do kernel. A forma como isto é feito tornar-se-á evidente em breve.
- Após a alocação, o atacante certifica-se de que nenhuma da memória no array da sonda é Cache. Existem várias maneiras de realizar isso, a mais simples das quais inclui instruções específicas do CPU para limpar a localização da memória do cache.
- o atacante, em seguida, continua a ler um byte do espaço de endereço do kernel. Lembre-se de nossa discussão anterior sobre memória virtual e tabelas de páginas que todos os kernels modernos tipicamente mapeiam todo o espaço de endereçamento virtual do kernel no processo do Usuário. Os sistemas operacionais dependem do fato de que cada entrada de tabela de página tem configurações de permissão, e que os programas de modo de usuário não estão autorizados a acessar a memória do kernel. Qualquer acesso desse tipo resultará em uma falha de página. Isso é realmente o que vai acontecer no Passo 3.
- No entanto, processadores modernos também executam a execução especulativa e executam antes da instrução de faulting. Assim, os passos 3-5 podem ser executados no pipeline da CPU antes que a falha seja levantada. Neste passo, o byte da memória do núcleo (que varia de 0-255) é multiplicado pelo tamanho da página do sistema, que é tipicamente 4096.
- Neste passo, o byte multiplicado da memória do kernel é então usado para ler a partir da matriz da sonda para um valor fictício. A multiplicação do byte por 4096 é para evitar um recurso de CPU chamado “prefetcher” de ler mais dados do que queremos no cache.nesta etapa, a CPU percebeu seu erro e voltou para a Etapa 3. No entanto, os resultados das instruções especuladas ainda são visíveis em cache. O atacante usa a funcionalidade do sistema operacional para capturar a instrução de faulting e continuar a execução (por exemplo, manusear SIGFAULT).
- no Passo 7, o atacante itera através e vê quanto tempo leva para ler cada um dos 256 bytes possíveis na sonda que poderia ter sido indexado pela memória do kernel. A CPU terá carregado um dos locais em cache e este local irá carregar substancialmente mais rápido do que todos os outros locais (que precisam ser lidos a partir da memória principal). Esta localização é o valor do byte na memória do kernel.
Usando a técnica acima, e o fato de que é prática padrão para os sistemas operacionais modernos mapear toda a memória física no espaço de endereçamento virtual do núcleo, um atacante pode ler toda a memória física do computador.
Agora, você pode estar se perguntando: “você disse que as tabelas de página têm bits de permissão. Como pode ser que o código do modo de usuário foi capaz de acessar especulativamente a memória do kernel?”A razão é que isto é um erro nos processadores Intel. Na minha opinião, não há uma boa razão, desempenho ou outra, para que isso seja possível. Lembre-se que todo acesso de memória virtual deve ocorrer através da TLB. É facilmente possível durante a execução especulativa verificar que um mapeamento em cache tem permissões compatíveis com o atual nível de privilégio de execução. A Intel hardware simplesmente não faz isso. Outros vendedores de processadores realizam uma verificação de permissão e bloqueiam a execução especulativa. Assim, tanto quanto sabemos, a fusão é uma vulnerabilidade da Intel.
Edit: parece que pelo menos um processador ARM também é suscetível a fusão, como indicado aqui e aqui.
mitigações de fusão
Meltdown é fácil de entender, trivial de explorar, e felizmente também tem uma mitigação relativamente simples (pelo menos conceptualmente — os desenvolvedores do kernel podem não concordar que é simples de implementar).
kernel page table isolation (KPTI)
Recall that in the section on virtual memory I described that all modern operating systems use a technique in which kernel memory is mapped into every user mode process virtual memory address space. Isto é por razões de desempenho e simplicidade. Significa que quando UM programa faz uma chamada de sistema, o kernel está pronto para ser usado sem mais trabalho. A solução para a fusão é deixar de realizar este mapeamento duplo.
a Figura 6 mostra uma técnica chamada de Kernel de Tabela de Página de Isolamento (KPTI). Isto basicamente resume-se a não mapear a memória do kernel em um programa quando ele está em execução no espaço do Usuário. Se não houver mapeamento presente, a execução especulativa não é mais possível e irá falhar imediatamente.
além de tornar o sistema operacional, o gerenciador de memória virtual (VMM) mais complicado, sem assistência de hardware esta técnica também irá diminuir consideravelmente as cargas de trabalho que fazem um grande número de modo de usuário para o modo kernel transições, devido ao fato de que as tabelas de página precisa ser modificado em cada transição e a TLB precisa ser liberado (dado que o TLB pode segurar obsoletos mapeamentos).
CPUs x86 mais recentes têm uma característica conhecida como ASID (address space ID) ou PCID (process context ID) que pode ser usada para tornar esta tarefa substancialmente mais barata (ARM e outras microarquitecturas tiveram Esta característica por anos). O PCID permite que um ID seja associado a uma entrada de TLB e, em seguida, apenas flush as entradas de TLB com esse ID. O uso do PCID torna o KPTI mais barato, mas ainda não é gratuito.
em resumo, a fusão é uma vulnerabilidade extremamente grave e fácil de explorar. Felizmente, ele tem uma mitigação relativamente simples que já foi implantado por todos os principais fornecedores de SO, a ressalva é que certas cargas de trabalho vai correr mais devagar até que o hardware futuro é explicitamente projetado para a separação de espaço de endereço descrito.
vulnerabilidade espectral
Spectre compartilha algumas propriedades de fusão e é composto por duas variantes. Ao contrário do colapso, a Spectre é substancialmente mais difícil de explorar, mas afeta quase todos os processadores modernos produzidos nos últimos vinte anos. Essencialmente, Spectre é um ataque contra a CPU moderna e o design do sistema operacional versus uma vulnerabilidade de segurança específica.
bypass de verificação de limites (variante do espectro 1)
a primeira variante do espectro é conhecida como bypass de verificação de limites.”Isto é demonstrado no seguinte excerto de código (que é o mesmo excerto de código que eu usei para introduzir a execução especulativa acima).
if (x < array1_size) {
y = array2 * 256];
}
No exemplo anterior, suponha que a seguinte seqüência de eventos:
- O atacante controla
x
. -
array1_size
não está em cache. - está em cache.
- A CPU considera que
x
é inferior aarray1_size
. (CPUs empregam vários algoritmos proprietários e heurísticas para determinar se especular, e é por isso que os detalhes de ataque para Spectre variam entre fornecedores de processadores e modelos.) - A CPU executa o corpo da declaração de fi enquanto aguarda a carga de
array1_size
, afectando a cache de uma forma semelhante à fusão. - o atacante pode então determinar o valor real de através de um de vários métodos. (See the research paper for more details of cache inference attacks.)
Spectre is considerably more difficult to exploit than Meltdown because this vulnerability does not depend on privilege increasing. O atacante deve convencer o kernel a executar o código e especular incorretamente. Normalmente, o atacante deve envenenar o motor de especulação e enganá-lo para adivinhar incorretamente. Dito isto, os pesquisadores têm mostrado várias proof-of-concept exploits.quero reiterar o incrível achado que esta façanha é. Pessoalmente, não considero isto uma falha de concepção da CPU, como a fusão em si. Considero esta uma revelação fundamental sobre a forma como o hardware e o software modernos funcionam em conjunto. O fato de que caches CPU podem ser usados indiretamente para aprender sobre os padrões de acesso tem sido conhecido por algum tempo. O fato de que caches CPU podem ser usados como um canal lateral para despejar memória de computador é surpreendente, tanto conceitualmente quanto em suas implicações.
injeção de alvo de ramo (variante 2 do espectro)
lembre-se que a ramificação indireta é muito comum em programas modernos. A variante 2 da Spectre utiliza a previsão indireta do ramo para envenenar a CPU em uma execução especular em um local de memória que ela nunca teria executado de outra forma. Se executar essas instruções pode deixar o estado para trás no cache que pode ser detectado usando ataques de inferência do cache, o atacante pode então descarregar toda a memória do kernel. Tal como a variante 1 da Spectre, a variante 2 da Spectre é muito mais difícil de explorar do que a fusão, no entanto, os investigadores têm demonstrado que a prova de trabalho do conceito explora a variante 2.as mitigações espectrais são substancialmente mais interessantes do que a mitigação da fusão. De fato, o jornal acadêmico Spectre escreve que não existem atualmente mitigações conhecidas. Parece que nos bastidores e em paralelo com o trabalho acadêmico, Intel (e provavelmente outros fornecedores de CPU) e os principais fornecedores de SO e nuvem têm trabalhado furiosamente por meses para desenvolver mitigações. Nesta seção Eu vou cobrir as várias mitigações que foram desenvolvidas e implantadas. Esta é a secção em que estou mais confuso, pois é incrivelmente difícil obter informações precisas, por isso estou a juntar as coisas a partir de várias fontes.
análise estática e esgrima (mitigação variante 1)
a única variante conhecida de mitigação 1 (bypass de verificação de limites) é a análise estática do código para determinar sequências de código que podem ser controladas pelo atacante para interferir com a especulação. Sequências de código vulneráveis podem ter uma instrução serializante, como lfence
inserida que interrompe a execução especulativa até que todas as instruções até a cerca tenham sido executadas. Deve ter-se cuidado ao inserir Instruções de vedação, uma vez que muitos podem ter impactos de desempenho graves.
Retpolina (mitigação variante 2)
a primeira mitigação espectral variante 2 (injeção alvo de ramificação) foi desenvolvida pela Google e é conhecida como “retpolina”.”Não sei se foi desenvolvido isoladamente pelo Google ou pelo Google em colaboração com a Intel. Eu especularia que foi desenvolvido experimentalmente pelo Google e depois verificado por engenheiros de hardware da Intel, mas não tenho a certeza. Detalhes sobre a abordagem” retpoline ” podem ser encontrados no artigo do Google sobre o tema. Vou resumi-los aqui (estou glosing sobre alguns detalhes, incluindo o underflow que são cobertos no papel).
Retpoline baseia-se no fato de que a chamada e o retorno das funções e as manipulações associadas da pilha são tão comuns em programas de computador que as CPUs são altamente otimizadas para executá-las. (Se você não está familiarizado com a forma como a pilha funciona em relação à chamada e retorno de funções este post é um bom iniciador.) Em poucas palavras, quando uma” chamada ” é realizada, o endereço de retorno é empurrado para a pilha. “ret” desliga o remetente e continua a execução. Hardware de execução especulativa vai lembrar o endereço de retorno empurrado e especulativamente continuar a execução nesse ponto.
a construção da retpolina substitui um salto indirecto para a localização da memória armazenada no registo r11
:
jmp *%r11
com:
call set_up_target; (1)
capture_spec: (4)
pause;
jmp capture_spec;
set_up_target:
mov %r11, (%rsp); (2)
ret; (3)
Let’s see what the previous assembly code does one step at a time and how it mitigates branch target injection.
- Nesta etapa, o código chama uma localização de memória que é conhecida no tempo de compilação assim é um deslocamento codificado duro e não indireto. Isto coloca o endereço de retorno de
capture_spec
na pilha. - o endereço de retorno da chamada é substituído com o alvo de salto real.um retorno é realizado no alvo real.
- Quando o CPU executar especulativamente, ele retornará em um loop infinito! Lembre-se que a CPU irá especular à frente até que as cargas de memória estejam completas. Neste caso, a especulação tem sido manipulada para ser capturada em um loop infinito que não tem efeitos colaterais que são observáveis para um atacante. Quando o CPU eventualmente executa o retorno real, ele abortará a execução especulativa que não teve efeito.na minha opinião, esta é uma mitigação verdadeiramente engenhosa. Parabéns aos engenheiros que o desenvolveram. A desvantagem desta mitigação é que requer que todo o software seja recompilado de tal forma que Ramos indiretos sejam convertidos em ramos retpoline. Para serviços de nuvem como o Google que possuem toda a pilha, recompilação não é um grande problema. Para outros, pode ser muito importante ou impossível.
IBRS, STIBP ,e IBPB (mitigação variante 2)
parece que, concomitantemente com o desenvolvimento de retpolina, Intel (e AMD, em certa medida) têm trabalhado furiosamente em mudanças de hardware para mitigar ataques de injeção alvo de ramificação. Os três novos recursos de hardware que estão sendo enviados como atualizações de microcódigo CPU são:
- especulação restrita indireta de ramo (IBRS)
- Predictors de ramo indireto de fio único (STIBP)
- Barreira de Predictor indireta de ramo (IBPB)
informação limitada sobre as novas características do microcódigo estão disponíveis a partir da Intel aqui. Eu tenho sido capaz de juntar aproximadamente o que essas novas funcionalidades fazem lendo a documentação acima e olhando para o kernel Linux e os patches hypervisor Xen. A partir da minha análise, cada recurso é potencialmente usado como segue:
- IBRS both flushes the branch prediction cache between privilege levels (user to kernel) and disables branch prediction on the sibling CPU thread. Lembre – se que cada núcleo de CPU normalmente tem dois threads de CPU. Parece que no CPUs moderno o hardware de previsão branch é compartilhado entre os threads. Isto significa que não só o código do modo de usuário pode envenenar o predictor do ramo antes de entrar no código do kernel, o código em execução no tópico da CPU irmão também pode envenená-lo. Activar o IBRS enquanto estiver no modo kernel impede essencialmente qualquer execução anterior no modo de utilizador e qualquer execução no tópico da CPU aparentada de afectar a previsão do ramo.
- STIBP parece ser um subconjunto de IBRS que apenas desactiva a previsão de ramificações na linha da CPU irmão. Tanto quanto eu posso dizer, o principal caso de uso para este recurso é para evitar que um thread de CPU irmão de envenenar o predictor de branch ao executar dois processos diferentes de modo de usuário (ou máquinas virtuais) no mesmo núcleo de CPU ao mesmo tempo. Honestamente, não está completamente claro para mim agora quando STIBP deve ser usado.
- IBPB parece descarregar o cache de previsão do ramo para o código a correr no mesmo nível de privilégio. Isso pode ser usado quando a alternância entre dois programas de modo de utilizador ou duas máquinas virtuais para garantir que o código anterior não interferir com o código que está prestes a ser executado (embora sem STIBP eu acredito que o código executado no irmão thread da CPU ainda pode envenenar o branch predictor).
a partir desta escrita, as principais mitigações que vejo que estão sendo implementadas para a vulnerabilidade de injeção alvo branch parecem ser retpolina e IBRS. Presumivelmente esta é a maneira mais rápida de proteger o kernel dos programas do modo de usuário ou do hypervisor dos hóspedes da máquina virtual. No futuro, eu esperaria tanto STIBP e IBPB para ser implantado dependendo do nível de paranóia de diferentes programas de modo de usuário interferindo uns com os outros.
o custo dos IBRS também parece variar muito entre arquiteturas de CPU, com novos processadores Intel Skylake sendo relativamente barato em comparação com processadores mais antigos. Em Lyft, vimos uma desaceleração de cerca de 20% em certos sistemas chamada cargas pesadas em casos AWS C4 quando as mitigações foram lançadas. Eu especularia que a Amazon lançou IBRS e potencialmente também retpolina, mas não tenho a certeza. Parece que o Google pode ter apenas rolado retpoline em sua nuvem.
ao longo do tempo, eu esperaria que os processadores eventualmente se mudassem para um modelo IBRS “always on” onde o hardware simplesmente usa para limpar a separação de predictor de ramo entre threads de CPU e corretamente descarrega o estado em mudanças de nível de privilégio. A única razão pela qual isso não seria feito hoje é o custo de desempenho aparente de reequipar esta funcionalidade em microarquitecturas já liberadas através de atualizações de microcódigos.
conclusão
é muito raro que um resultado de investigação altere fundamentalmente a forma como os computadores são construídos e executados. A fusão e a Spectre fizeram isso mesmo. Estas descobertas irão alterar substancialmente o design de hardware e software nos próximos 7-10 anos (o próximo ciclo de hardware CPU), uma vez que os designers levam em conta a nova realidade das possibilidades de fuga de dados através de canais laterais de cache.entretanto, as conclusões do colapso e do espectro e as mitigações associadas terão implicações substanciais para os utilizadores de computadores nos próximos anos. A curto prazo, as atenuações terão um impacto de desempenho que pode ser substancial, dependendo da carga de trabalho e hardware específico. Isso pode exigir mudanças operacionais para algumas infra-estruturas (por exemplo, em Lyft estamos agressivamente mover cargas de trabalho para a AWS C5 instâncias devido ao fato de que IBRS aparece para executar substancialmente mais rápido no Skylake processadores e o novo Nitro hypervisor fornece interrupções diretamente para os hóspedes, utilizando SR-IOV e APICv, removendo muitos máquina virtual sai para IO cargas de trabalho pesadas). Os usuários de computador de Desktop também não são imunes, devido a ataques de navegador de prova de conceito usando JavaScript que os vendedores de SO e navegador estão trabalhando para mitigar. Além disso, devido à complexidade das vulnerabilidades, é quase certo que os pesquisadores de segurança vão encontrar novas façanhas não cobertas pelas mitigações atuais que terão de ser corrigidas.apesar de adorar trabalhar na Lyft e sentir que o trabalho que estamos a fazer no espaço de infra-estrutura de sistemas microservice é um dos trabalhos mais impactantes que estão a ser feitos na indústria neste momento, eventos como este fazem-me sentir falta de trabalhar em sistemas operativos e hipervisores. Estou extremamente ciumento do trabalho heróico que foi feito nos últimos seis meses por um grande número de pessoas na pesquisa e mitigação das vulnerabilidades. Eu teria adorado ter feito parte disso!
ler Mais
- Colapso e Spectre trabalhos acadêmicos: https://spectreattack.com/
- o Google Project Zero post no blog: https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
- Intel Espectro de hardware atenuações: https://software.intel.com/sites/default/files/managed/c5/63/336996-Speculative-Execution-Side-Channel-Mitigations.pdf
- Retpoline post do blog: https://support.google.com/faqs/answer/7625886
- Bom resumo de informações conhecidas: https://github.com/marcan/speculation-bugs/blob/master/README.md