Rosetta 2 em um Mac com Apple Silicon
Um Mac com Apple Silicon é capaz de executar código compilado para o conjunto de instruções x86_64 com um mecanismo chamado Rosetta 2. Há dois tipos de tradução oferecidos: dinâmica e antecipada.
Tradução dinâmica
No canal de tradução dinâmica (JIT), um objeto Mach x86_64 é identificado cedo no caminho de execução da imagem. Quando essas imagens são encontradas, o kernel transfere o controle para uma ponta especial de tradução Rosetta em vez de para o editor de links dinâmicos, dyld(1)
. A ponta de tradução traduz então as páginas x86_64 durante a execução da imagem. A tradução ocorre integralmente dentro do processo. O kernel ainda compara os hashes de código de cada página x86_64 com a assinatura de código anexada ao binário conforme falhas são encontradas na página. No caso de uma incongruência de hash, o kernel exige a política de remediação apropriada para tal processo.
Tradução antecipada
No caminho de tradução antecipada (AOT), os binários x86_64 são lidos do armazenamento em momentos que o sistema considera ideais para a responsividade desse código. Os artefatos traduzidos são gravados no armazenamento como um tipo especial de arquivo de objeto Mach. Esse arquivo se assemelha a uma imagem executável, mas é marcado para indicar ser o produto traduzido de outra imagem.
Nesse modelo, o artefato AOT deriva todas as suas informações de identidade da imagem executável x86_64 original. Para exigir esse vínculo, uma entidade de espaço do usuário privilegiada assina o artefato de tradução com uma chave específica do dispositivo, gerenciada pelo Secure Enclave. A chave é liberada apenas para a entidade de espaço do usuário privilegiada, que é identificada como tal ao usar um direito restrito. O diretório de código criado para o artefato de tradução inclui o hash do diretório de código da imagem executável x86_64 original. A assinatura no artefato de tradução em si é conhecida como assinatura suplementar.
O canal AOT começa de maneira similar ao canal JIT, com o kernel transferindo o controle para o tempo de execução Rosetta em vez de para o editor de links dinâmicos, dyld(1)
. Mas o tempo de execução Rosetta envia uma consulta de comunicação interprocessual (IPC) para o serviço de sistema Rosetta, perguntando se há uma tradução AOT disponível para a imagem executável atual. Se encontrada, o serviço Rosetta fornece um controle para essa tradução, sendo ela mapeada no processo e executada. Durante a execução, o kernel exige os hashes de diretório de código do artefato de tradução, os quais são autenticados pela assinatura com raiz na chave de assinatura específica do dispositivo. Os hashes de diretório de código da imagem x86_64 original não são envolvidos nesse processo.
Os artefatos traduzidos são armazenados em um Cofre de Dados que não pode ser acessado no tempo de execução por nenhuma entidade além do serviço Rosetta. O serviço Rosetta gerencia o acesso ao seu cache ao distribuir descritores de arquivos somente leitura a artefatos de tradução individuais, o que limita o acesso ao cache de artefatos AOT. A comunicação interprocessual e o rastro dependente desse serviço são mantidos intencionalmente estreitos para limitar a superfície de ataque.
Se o hash do diretório de código da imagem x86_64 original não coincidir com o hash codificado na assinatura do artefato de tradução AOT, esse resultado é considerado como uma assinatura de código inválida e ações de exigências apropriadas são tomadas.
Se um processo remoto solicitar ao kernel uma consulta de direitos ou de outras propriedades de identidade de código de um executável AOT traduzido, as propriedade de identidade da imagem x86_64 original são retornadas ao processo.
Conteúdo do cache de confiança estático
O macOS 11 ou posterior é fornecido com binários que contêm partes de código de computador x86_64 e arm64. Em um Mac com Apple Silicon, o usuário pode decidir executar a parte x86_64 de um binário do sistema através do canal Rosetta — para carregar um plug-in que não tenha uma variante arm64 nativa, por exemplo. Para oferecer suporte a essa abordagem, o cache de confiança estático fornecido com o macOS geralmente contém três hashes de diretório de código por arquivo de objeto Mach:
Um hash do diretório de código da parte arm64
Um hash do diretório de código da parte x86_64
Um hash do diretório de código da tradução AOT da parte x86_64
O procedimento de tradução AOT do Rosetta é determinista, no sentido de que ele reproduz uma saída idêntica para qualquer entrada determinada, independentemente de quando a tradução foi realizada ou em qual dispositivo ela foi feita.
Durante a compilação do macOS, todo arquivo de objeto Mach é executado pelo canal de tradução AOT do Rosetta associado à versão do macOS sendo compilada, e o hash de diretório de código resultante é gravado no cache de confiança. Por motivos de eficiência, os produtos traduzidos em si não são fornecidos com o sistema operacional e são reconstituídos sob demanda quando o usuário os solicita.
Quando uma imagem x86_64 está sendo executada em um Mac com Apple Silicon, se o hash de diretório de código dessa imagem estiver no cache de confiança estático, também espera-se que o hash de diretório de código do artefato AOT resultante esteja no cache de confiança estático. Tais produtos não são assinados pela chave específica do dispositivo porque a autoridade de assinatura tem suas raízes na cadeia de inicialização segura da Apple.
Código x86_64 não assinado
Um Mac com Apple Silicon não permite a execução do código arm64 nativo sem que uma assinatura válida esteja anexada. Essa assinatura pode ser tão simples quanto uma assinatura de código “ad hoc” (cf. codesign(1)
) que não tenha nenhuma identidade real da metade secreta de um par de chaves assimétricas (ela é, simplesmente, uma medida não autenticada do binário).
Para oferecer compatibilidade binária, o código x86_64 traduzido tem permissão para ser executado através do Rosetta sem nenhuma informação de assinatura. Nenhuma identidade específica é passada a esse código pelo procedimento de assinatura do Secure Enclave específico do dispositivo, e ele é executado com, precisamente, as mesmas limitações de execução do código nativo não assinado em um Mac baseado em Intel.