paint-brush
Segurança microarquitetônica do AWS Firecracker VMM: históricopor@autoencoder
386 leituras
386 leituras

Segurança microarquitetônica do AWS Firecracker VMM: histórico

Muito longo; Para ler

Este artigo de pesquisa investiga o quão seguro o Firecracker é contra ataques de microarquitetura.
featured image - Segurança microarquitetônica do AWS Firecracker VMM: histórico
Auto Encoder: How to Ignore the Signal Noise HackerNoon profile picture
0-item

Autores:

(1) Zane Weissman, Instituto Politécnico de Worcester Worcester, MA, EUA {[email protected]};

(2) Thomas Eisenbarth, Universidade de Lübeck Lübeck, SH, Alemanha {[email protected]};

(3) Thore Tiemann, Universidade de Lübeck Lübeck, SH, Alemanha {[email protected]};

(4) Berk Sunar, Instituto Politécnico de Worcester Worcester, MA, EUA {[email protected]}.

Tabela de links

2. ANTECEDENTES

2.1KVM

A máquina virtual baseada em kernel Linux (KVM) [29] fornece uma abstração dos recursos de virtualização assistida por hardware, como Intel VT-x ou AMD-V, que estão disponíveis em CPUs modernas. Para suportar a execução quase nativa, um modo convidado é adicionado ao kernel Linux, além do modo kernel e do modo de usuário existentes. Se estiver no modo convidado Linux, o KVM faz com que o hardware entre no modo de virtualização de hardware que replica os privilégios do anel 0 e do anel 3.[1]


Com o KVM, a virtualização de E/S é realizada principalmente no espaço do usuário pelo processo que criou a VM, conhecido como VMM ou hipervisor, em contraste com os hipervisores anteriores que normalmente exigiam um processo de hipervisor separado [41]. Um hipervisor KVM fornece a cada convidado da VM sua própria região de memória separada da região de memória do processo que criou o convidado. Isto é verdade para convidados criados a partir do espaço do kernel, bem como do espaço do usuário. Cada VM mapeia para um processo no host Linux e cada CPU virtual atribuída ao convidado é um thread nesse processo host. O processo de hipervisor do espaço do usuário da VM faz chamadas de sistema para KVM somente quando a execução privilegiada é necessária, minimizando a troca de contexto e reduzindo a VM à superfície de ataque do kernel. Além de impulsionar melhorias de desempenho em todos os tipos de aplicativos, esse design permitiu o desenvolvimento de hipervisores leves que são especialmente úteis para sandbox de programas individuais e suporte a ambientes de nuvem onde muitas VMs estão sendo executadas ao mesmo tempo.

2.2 Computação em nuvem sem servidor

Um modelo cada vez mais popular para computação em nuvem é a computação sem servidor, na qual o CSP gerencia a escalabilidade e a disponibilidade dos servidores que executam o código do usuário. Uma implementação da computação sem servidor é chamada de função como serviço (FaaS). Neste modelo, um usuário da nuvem define funções que são chamadas conforme necessário através da interface de programação de aplicativos (API) do provedor de serviços (daí o nome “função como serviço”) e o CSP gerencia a alocação de recursos no servidor que executa o função do usuário (daí o nome “computação sem servidor” – o usuário não gerencia o servidor). Da mesma forma, a computação de contêiner como serviço (CaaS) executa contêineres, pacotes de tempo de execução portáteis, sob demanda. O gerenciamento centralizado de servidores de FaaS e CaaS é economicamente atraente tanto para CSPs quanto para usuários. O CSP pode gerenciar as cargas de trabalho de seus usuários da maneira que desejar, otimizar para obter custos operacionais mínimos e implementar preços flexíveis em que os usuários pagam pelo tempo de execução que utilizam. O usuário não precisa se preocupar com o projeto ou gerenciamento da infraestrutura do servidor e, assim, reduz os custos de desenvolvimento e terceiriza os custos de manutenção para o CSP a uma taxa relativamente pequena e previsível.

2.3 MicroVMs e AWS Firecracker

Os provedores de FaaS e CaaS usam uma variedade de sistemas para gerenciar funções e contêineres em execução. Sistemas de contêineres como Docker, Podman e LXD fornecem uma maneira conveniente e leve de empacotar e executar aplicativos em área restrita em qualquer ambiente. No entanto, em comparação com as máquinas virtuais utilizadas para muitas formas mais tradicionais de computação em nuvem, os contentores oferecem menos isolamento e, portanto, menos segurança. Nos últimos anos, os principais CSPs introduziram microVMs que suportam contêineres tradicionais com virtualização leve para segurança extra. [1, 55] A eficiência da virtualização de hardware com KVM e o design leve de microVMs significa que o código em sistemas virtualizados, conteinerizados ou semelhantes a contêineres pode ser executado quase tão rápido quanto o código não virtualizado e com sobrecarga comparável a um contêiner tradicional.


Firecracker [1] é um microVM desenvolvido pela AWS para isolar cada uma das cargas de trabalho AWS Lambda FaaS e AWS Fargate CaaS em uma VM separada. Ele suporta apenas convidados Linux em hosts x86 ou ARM Linux-KVM e fornece um número limitado de dispositivos disponíveis para sistemas convidados. Essas limitações permitem que o Firecracker seja muito leve no tamanho de sua base de código e na sobrecarga de memória para uma VM em execução, além de ser muito rápido para inicializar ou desligar. Além disso, o uso de KVM alivia os requisitos do Firecracker, uma vez que algumas funções de virtualização são gerenciadas por chamadas de sistema do kernel e o sistema operacional host gerencia VMs como processos padrão. Devido à sua pequena base de código escrita em Rust, o Firecracker é considerado muito seguro, embora falhas de segurança tenham sido identificadas em versões anteriores (consulte CVE-2019-18960). Curiosamente, o white paper do Firecracker declara que os ataques de microarquitetura estão no escopo de seu modelo de invasor [1], mas carece de uma análise de segurança detalhada ou contramedidas especiais contra ataques de microarquitetura além das recomendações comuns de configuração segura do sistema para o kernel convidado e host. A documentação do Firecracker fornece recomendações de segurança do sistema [8] que incluem uma lista específica de contramedidas, que abordamos na seção 2.6.1.

2.4 Fusão e MDS

Em 2018, o ataque Meltdown [32] mostrou que os dados acessados especulativamente poderiam ser exfiltrados através dos limites de segurança, codificando-os em um canal lateral de cache. Isso logo levou a toda uma classe de ataques semelhantes, conhecidos como amostragem de dados microarquiteturais (MDS), incluindo Fallout [14], Rogue In-flight Data Load (RIDL) [50], TSX Asynchronous Abort (TAA) [50], e Carga de Zumbis [46]. Todos esses ataques seguem o mesmo padrão geral para explorar a execução especulativa:


(1) A vítima executa um programa que lida com dados secretos, e os dados secretos passam por um cache ou buffer de CPU.


(2) O invasor executa uma instrução especificamente escolhida que fará com que a CPU preveja erroneamente que os dados secretos serão necessários. A CPU encaminha os dados secretos para as instruções do invasor.


(3) Os dados secretos encaminhados são usados como índice para uma leitura de memória em um array que o invasor está autorizado a acessar, fazendo com que uma linha específica desse array seja armazenada em cache.


(4) A CPU termina a verificação dos dados e decide que os dados secretos foram encaminhados incorretamente e reverte o estado de execução para antes de serem encaminhados, mas o estado do cache não é revertido. (5) O invasor investiga todo o array para ver qual linha foi armazenada em cache; o índice dessa linha é o valor dos dados secretos.


A vulnerabilidade Meltdown original tinha como alvo o encaminhamento de cache e permitia a extração de dados dessa maneira de qualquer endereço de memória presente no cache. Os ataques MDS têm como alvo buffers menores e mais específicos na microarquitetura on-core e, portanto, constituem uma classe de ataques relacionada, mas distinta, que são mitigados de maneira significativamente diferente. Embora o Meltdown tenha como alvo a memória principal que é atualizada com relativa pouca frequência e compartilhada entre todos os núcleos, threads e processos, os ataques MDS tendem a ter como alvo buffers locais aos núcleos (embora às vezes compartilhados entre threads) e atualizados com mais frequência durante a execução.


2.4.1 Variantes Básicas do MDS . A Figura 1 mostra os principais caminhos de ataque MDS conhecidos em CPUs Intel e os nomes dados às diferentes variantes pela Intel e pelos pesquisadores que os relataram. De forma mais ampla, a Intel categoriza as vulnerabilidades do MDS em suas CPUs pelo buffer específico a partir do qual os dados são encaminhados especulativamente, uma vez que esses buffers tendem a ser usados para diversas operações diferentes. As vulnerabilidades RIDL MDS podem ser categorizadas como Microarchitectural Load Port Data Sampling (MLPDS), para variantes que vazam da porta de carregamento da CPU, e Microarchitectural Fill Buffer Data Sampling (MFBDS), para variantes que vazam do LFB da CPU. Na mesma linha, a Intel chama a vulnerabilidade Fallout de Microarchitectural Store Buffer Data Sampling (MSBDS), pois envolve um vazamento do buffer de armazenamento. Vector Register Sampling (VRS) é uma variante do MSBDS que tem como alvo dados que são manipulados por operações vetoriais à medida que passam pelo buffer de armazenamento. O bypass VERW explora um bug no


Figura 1: Principais caminhos de ataque MDS e nomes de variantes em CPUs Intel. Os nomes azuis no topo são nomes de vulnerabilidades fornecidos pela Intel; os nomes vermelhos na parte inferior são nomes dados por pesquisadores ou nomes de artigos nos quais as vulnerabilidades foram relatadas. Nem todos os tipos de falhas funcionam com todas as vulnerabilidades em todos os sistemas – o encaminhamento e a codificação bem-sucedidos durante a execução especulativa dependem da microarquitetura exata, incluindo quaisquer contramedidas de microarquitetura que estejam em vigor, portanto, catalogar todas as combinações conhecidas estaria além do escopo deste artigo.


correções de microcódigo para MFBDS que carrega dados obsoletos e potencialmente secretos no LFB. O mecanismo básico de vazamento é o mesmo, e o desvio VERW pode ser considerado um caso especial de MFBDS. A amostragem de remoção de dados L1 (L1DES) é outro caso especial de MFBDS, onde os dados despejados do cache de dados L1 passam pelo LFB e se tornam vulneráveis a um ataque MDS. Notavelmente, L1DES é um caso em que o invasor pode realmente acionar a presença dos dados secretos na CPU (despejando-os), enquanto outros ataques MDS dependem diretamente do processo da vítima acessando os dados secretos para trazê-los para o buffer correto da CPU.


2.4.2 Medusa. Medusa [37] é uma categoria de ataques MDS classificados pela Intel como variantes MLPDS [25]. As vulnerabilidades Medusa exploram os algoritmos imperfeitos de correspondência de padrões usados para combinar especulativamente armazenamentos no buffer write-combine (WC) dos processadores Intel. A Intel considera o buffer WC como parte da porta de carregamento, portanto a Intel categoriza esta vulnerabilidade como um caso de MLPDS. Existem três variantes conhecidas do Medusa, cada uma explorando um recurso diferente do buffer de combinação de gravação para causar um vazamento especulativo:


Indexação de cache: uma carga com falha é combinada especulativamente com uma carga anterior com um deslocamento de linha de cache correspondente.


Encaminhamento de armazenamento para carga desalinhado: um armazenamento válido seguido por uma carga dependente que aciona uma falha de memória desalinhada faz com que dados aleatórios do WC sejam encaminhados.


Shadow REP MOV : uma instrução REP MOV com falha seguida por uma carga dependente vaza os dados de um REP MOV diferente.


2.4.3 Anulação assíncrona do TSX. A vulnerabilidade de hardware TSX Asynchronous Abort (TAA) [24] fornece um mecanismo de especulação diferente para realizar um ataque MDS. Enquanto os ataques MDS padrão acessam dados restritos com uma execução especulada padrão, o TAA usa uma transação de memória atômica implementada pelo TSX. Quando uma transação de memória atômica encontra uma interrupção assíncrona, por exemplo, porque outro processo lê uma linha de cache marcada para uso pela transação ou porque a transação encontra uma falha, todas as operações na transação são revertidas para o estado arquitetural antes do início da transação. Porém, durante esse rollback, as instruções dentro da transação que já iniciaram a execução podem continuar a execução especulativa, como nas etapas (2) e (3) de outros ataques MDS. O TAA afeta todos os processadores Intel que suportam TSX, e no caso de certos processadores mais novos que não são afetados por outros ataques MDS, mitigações de MDS ou mitigações específicas de TAA (como desabilitar TSX) devem ser implementadas em software para proteção contra TAA [24].


2.4.4 Mitigações. Embora as vulnerabilidades da classe Meltdown e MDS explorem operações de microarquitetura de baixo nível , elas podem ser atenuadas com patches de firmware de microcódigo nas CPUs mais vulneráveis.


Isolamento da tabela de páginas. Historicamente, as tabelas de páginas do kernel foram incluídas nas tabelas de páginas de processos no nível do usuário para que um processo no nível do usuário possa fazer uma chamada de sistema para o kernel com sobrecarga mínima. O isolamento da tabela de páginas (proposto pela primeira vez por Gruss et al. como KAISER [19]) mapeia apenas a memória mínima necessária do kernel na tabela de páginas do usuário e introduz uma segunda tabela de páginas acessível apenas pelo kernel. Com o processo do usuário incapaz de acessar a tabela de páginas do kernel, os acessos a todos, exceto uma fração pequena e especificamente escolhida da memória do kernel, são interrompidos antes de atingirem os caches de nível inferior onde um ataque Meltdown começa.


Substituição de buffer. Os ataques MDS direcionados aos buffers de CPU no núcleo exigem uma defesa de nível inferior e mais direcionada. A Intel introduziu uma atualização de microcódigo que substitui buffers vulneráveis quando o cache de dados de primeiro nível (L1d) (um alvo comum de ataques de canal lateral de temporização de cache) é liberado ou a instrução VERW é executada [25]. O kernel pode então proteger contra ataques MDS acionando uma substituição de buffer ao alternar para um processo não confiável.


A mitigação de substituição de buffer tem como alvo os ataques MDS em sua origem, mas é imperfeita, para dizer o mínimo. Os processos permanecem vulneráveis a ataques de threads em execução simultânea no mesmo núcleo quando o SMT está habilitado (uma vez que ambos os threads compartilham buffers vulneráveis sem que o processo ativo realmente mude em qualquer um dos threads). Além disso, logo após a atualização do microcódigo de substituição do buffer original, a equipe RIDL descobriu que em algumas CPUs Skylake, os buffers foram substituídos por dados obsoletos e potencialmente confidenciais [50] e permaneceram vulneráveis mesmo com mitigações habilitadas e SMT desabilitado. Ainda outros processadores são vulneráveis a ataques TAA, mas não a ataques MDS não TAA, e não receberam uma atualização de microcódigo de substituição de buffer e, como tal, exigem que o TSX seja completamente desativado para evitar ataques MDS [20, 24].

2.5 Espectro


Em 2018, Jan Horn e Paul Kocher [30] relataram de forma independente as primeiras variantes do Spectre. Desde então, muitas variantes diferentes do Spectre [22, 30, 31, 33] e subvariantes [10, 13, 16, 28, 52] foram descobertas. Os ataques Spectre fazem com que a CPU acesse especulativamente a memória que é arquitetonicamente inacessível e vaze os dados para o estado arquitetônico. Portanto, todas as variantes do Spectre consistem em três componentes [27]:


O primeiro componente é o gadget Spectre que é executado especulativamente. As variantes do Spectre são geralmente separadas pela fonte da previsão errada que exploram. O resultado de uma ramificação direta condicional, por exemplo, é previsto pela Tabela de Histórico de Padrões (PHT). Previsões erradas do PHT podem levar a um desvio especulativo de verificação de limites para instruções de carregamento e armazenamento [13, 28, 30]. O alvo da ramificação de um salto indireto é previsto pelo Branch Target Buffer (BTB). Se um invasor puder influenciar o resultado de uma previsão incorreta do BTB, então serão possíveis ataques especulativos de programação orientada ao retorno [10, 13, 16, 30]. O mesmo se aplica às previsões servidas pelo Return Stack Buffer (RSB) que prevê endereços de retorno durante a execução das instruções de retorno [13, 31, 33]. Resultados recentes mostraram que algumas CPUs modernas usam o BTB para suas previsões de endereço de retorno se o RSB estiver com estouro insuficiente [52]. Outra fonte de ataques Spectre é a previsão de dependências de armazenamento para carregamento. Se uma carga for mal prevista para não depender de um armazenamento anterior, ela será executada especulativamente em dados obsoletos, o que pode levar a um desvio de armazenamento especulativo [22]. Todos esses gadgets não são exploráveis por padrão, mas dependem dos outros dois componentes discutidos agora.


O segundo componente é como um invasor controla as entradas dos gadgets mencionados acima. Os invasores podem definir valores de entrada do gadget diretamente por meio da entrada do usuário, conteúdo de arquivos, pacotes de rede ou outros mecanismos de arquitetura. Por outro lado, os invasores podem injetar dados no gadget transitoriamente por meio de injeção de valor de carga [12] ou injeção de valor de ponto flutuante [42]. Os invasores serão capazes de controlar com êxito as entradas do gadget se puderem influenciar quais dados ou instruções serão acessados ou executados durante a janela de especulação.


O terceiro componente é o canal secreto usado para transferir o estado microarquitetônico especulativo para um estado arquitetônico e, portanto, exfiltrar os dados acessados especulativamente para um ambiente persistente. Canais secretos de cache [39, 40, 54] são aplicáveis se o código da vítima realizar um acesso transitório à memória dependendo de dados secretos acessados especulativamente [30]. Se um segredo for acessado especulativamente e carregado em um buffer no núcleo, um invasor pode contar com um canal baseado em MDS [14, 46, 50] para transferir transitoriamente os dados exfiltrados para o thread do invasor, onde os dados são transferidos para a arquitetura. estado através, por exemplo, de um canal secreto de cache. Por último, mas não menos importante, se a vítima executar código dependendo de dados secretos, o invasor poderá descobrir o segredo observando a contenção de portas [3, 11, 18, 43, 44].


2.5.1 Mitigações. Muitas contramedidas foram desenvolvidas para mitigar as várias variantes do Spectre. Uma variante específica do Spectre é efetivamente desativada se um dos três componentes necessários for removido. É improvável que um invasor sem controle sobre as entradas dos gadgets Spectre lance um ataque com sucesso. O mesmo é verdade se não estiver disponível um canal secreto para transformar o estado especulativo num estado arquitetónico. Mas como isso geralmente é difícil de garantir, as contramedidas do Spectre concentram-se principalmente em impedir previsões erradas. A inserção de instruções lfence antes de seções críticas de código desabilita a execução especulativa além deste ponto e pode, portanto, ser usada como uma contramedida genérica. Mas devido à sua sobrecarga de alto desempenho, foram desenvolvidas contramedidas mais específicas. As contramedidas Spectre-BTB incluem Retpoline [48] e atualizações de microcódigo como IBRS, STIBP ou IBPB [23]. Spectre-RSB e Spectre-BTB-via-RSB podem ser atenuados preenchendo o RSB com valores para substituir entradas maliciosas e evitar o transbordamento do RSB ou instalando atualizações de microcódigo IBRS. O Spectre-STL pode ser mitigado pela atualização do microcódigo SSBD [23]. Outra opção drástica para impedir que um invasor adultere buffers de previsão de ramificação compartilhados é desabilitar o SMT. Desabilitar o SMT particiona efetivamente os recursos de hardware de previsão de ramificação entre locatários simultâneos, ao custo de uma perda significativa de desempenho.

2.6 Modelo de isolamento da AWS

O Firecracker foi desenvolvido especificamente para aplicativos sem servidor e de contêiner [1] e atualmente é usado pelo Fargate CaaS e Lambda FaaS da AWS. Em ambos os modelos de serviço, o Firecracker é o sistema de isolamento principal que oferece suporte a cada tarefa individual do Fargate ou evento Lambda. Ambos os modelos de serviço também são projetados para executar um grande número de tarefas relativamente pequenas e de curta duração. A AWS relaciona os requisitos de design para o sistema de isolamento que eventualmente se tornou o Firecracker da seguinte forma:


Isolamento : Deve ser seguro que múltiplas funções sejam executadas no mesmo hardware, protegidas contra escalonamento de privilégios, divulgação de informações, canais secretos e outros riscos.


Overhead e Densidade: Deve ser possível executar milhares de funções em uma única máquina, com desperdício mínimo.


Desempenho: as funções devem funcionar de forma semelhante à execução nativa. O desempenho também deve ser consistente e isolado do comportamento dos vizinhos no mesmo hardware.


Compatibilidade : Lambda permite que funções contenham binários e bibliotecas arbitrárias do Linux. Eles devem ser suportados sem alterações de código ou recompilação.


Troca Rápida: Deve ser possível iniciar novas funções e limpar funções antigas rapidamente.


Alocação suave: Deve ser possível comprometer excessivamente CPU, memória e outros recursos, com cada função consumindo apenas os recursos de que necessita, e não os recursos aos quais tem direito. [1]


Estamos particularmente interessados no requisito de isolamento e enfatizamos que os ataques microarquiteturais são declarados no escopo do modelo de ameaça Firecracker. A página “design” no repositório Firecracker Git público da AWS elabora o modelo de isolamento e fornece um diagrama útil que reproduzimos na Figura 2. Este diagrama refere-se principalmente à proteção contra escalonamento de privilégios. A camada mais externa de proteção é o jailer, que usa técnicas de isolamento de contêiner para limitar o acesso do Firecracker ao kernel do host enquanto executa o VMM e outros componentes de gerenciamento.


Figura 2: A AWS fornece este diagrama de contenção de ameaças em um documento de design no repositório Firecracker GitHub [6]. Neste modelo, o jailer fornece proteções semelhantes a contêineres em torno do VMM do Firecracker, da API, do serviço de metadados de instância (IMDS), todos executados no espaço do usuário host, e da carga de trabalho do cliente, que é executada dentro da máquina virtual. A VM isola a carga de trabalho do cliente no convidado, garantindo que ela interaja diretamente apenas com elementos predeterminados do host (tanto no espaço do usuário quanto no kernel).


do Firecracker como threads de um único processo no espaço do usuário host. Dentro do processo do Firecracker, a carga de trabalho do usuário é executada em outros threads. Os threads de carga de trabalho executam o sistema operacional convidado da máquina virtual e quaisquer programas em execução no convidado. A execução do código do usuário na máquina virtual guest restringe sua interação direta com o host a interações pré-arranjadas com KVM e certas partes dos threads de gerenciamento do Firecracker. Portanto, da perspectiva do kernel host, o VMM e a VM, incluindo o código do usuário, são executados no mesmo processo. Esta é a razão pela qual a AWS afirma que cada VM reside em um único processo. Mas, como a VM é isolada por meio de técnicas de virtualização de hardware, o código do usuário, o kernel convidado e o VMM operam em espaços de endereço separados. Portanto, o código do convidado não pode acessar de forma arquitetural ou transitória o VMM ou os endereços de memória do kernel convidado, pois eles não são mapeados no espaço de endereço do convidado. A superfície de ataque microarquitetural restante é limitada a ataques MDS que vazam informações dos buffers internos da CPU, ignorando os limites do espaço de endereço e ataques Spectre, onde um invasor manipula a previsão de ramificação de outros processos para vazar informações por conta própria.


Não mostrado na Figura 2, mas igualmente importante para o modelo de ameaças da AWS, é o isolamento das funções umas das outras quando o hardware é compartilhado, especialmente à luz do requisito de alocação suave . Além do fato de que comprometer o kernel do host pode comprometer a segurança de qualquer convidado, os ataques de microarquitetura direcionados ao hardware do host também podem ameaçar diretamente o código do usuário. Como um único processo do Firecracker contém todos os threads necessários para executar uma máquina virtual com uma função de usuário, a alocação suave pode simplesmente ser executada pelo sistema operacional host [1]. Isso significa que os sistemas padrão de isolamento de processos do Linux estão implementados além do isolamento de máquinas virtuais.


2.6.1 Recomendações de segurança do Firecracker. A documentação do Firecracker também recomenda as seguintes precauções para proteção contra canais laterais microarquitetônicos [8]:


• Desativar SMT


• Ativar o isolamento da tabela de páginas do kernel


• Desativar a mesclagem de páginas kame do kernel


• Use um kernel compilado com mitigação Spectre-BTB (por exemplo, IBRS e IBPB em x86)


• Verifique a mitigação do Spectre-PHT


• Habilitar mitigação L1TF • Habilitar mitigação Spectre-STL


• Use memória com mitigação Rowhammer


• Desative a troca ou use a troca segura


Este artigo está disponível no arxiv sob licença CC BY-NC-ND 4.0 DEED.


[1] Os anéis virtualizados 0 e 3 são uma das principais razões pelas quais a execução de código quase nativo é alcançada.