Computer Science › Sistemas
O hardware distingue exatamente dois modos de execução, kernel e usuário, e impõe quais instruções e qual memória cada um pode tocar: o único mecanismo a partir do qual toda outra garantia de proteção no nível do SO desta disciplina é, no fim das contas, construída.
Uma chamada de sistema, uma interrupção de hardware e uma page fault parecem completamente diferentes para o programador, mas a CPU trata as três com exatamente o mesmo mecanismo de trap: salva o estado atual, salta para um ponto de entrada fixo do kernel e deixa o kernel descobrir por que foi chamado.
Rastreando uma única chamada como write() desde um invólucro de biblioteca em espaço de usuário, passando pela instrução de trap, entrando na tabela de chamadas de sistema do kernel, atravessando a rotina real do kernel e voltando: a maquinaria concreta por trás de todo serviço de SO que um programa jamais solicita.
Todo ponteiro e todo tamanho que um programa de usuário entrega a uma chamada de sistema é uma alegação na qual o kernel não pode confiar. O mesmo modo de falha de segurança de memória já visto no nível da aplicação se torna catastrófico aqui, porque o código que confia na entrada ruim está rodando com privilégio total.
O operador | do shell conecta a saída padrão de um processo diretamente à entrada padrão de outro por meio de um buffer de bytes gerenciado pelo kernel: a forma de IPC mais simples, mais antiga e ainda mais comum em qualquer sistema tipo Unix.
O kernel mapeia exatamente a mesma página física em dois espaços de endereçamento que de resto são isolados, dando aos dois processos acesso direto e sem cópia aos mesmos bytes: o mecanismo de IPC mais rápido que existe, e aquele que devolve toda a responsabilidade de sincronização diretamente à mecânica de locks e semáforos já coberta.
Em vez de um buffer compartilhado bruto ou de um fluxo de bytes indiferenciado, o kernel gerencia mensagens discretas e tipadas, com as suas próprias garantias de entrega e ordem. Isso troca a velocidade bruta da memória compartilhada por segurança, já que o kernel media todo acesso em vez de confiar que os processos se coordenem corretamente por conta própria.
A API de sockets de Berkeley apresenta a comunicação com um processo na mesma máquina e com um processo do outro lado do planeta pela exatamente mesma interface de read/write: a abstração para a qual os mecanismos de IPC desta disciplina convergem, e aquela sobre a qual uma futura disciplina de redes constrói diretamente.
Um hypervisor roda um sistema operacional convidado inteiro (kernel, drivers e tudo mais) como se ele tivesse uma máquina inteira só para si, interceptando cada instrução privilegiada que o convidado tenta executar e emulando o seu efeito em vez de deixá-la tocar o hardware real.
O trap-and-emulate sozinho não conseguia virtualizar o conjunto de instruções x86 real, porque um punhado de instruções privilegiadas simplesmente não fazia trap quando rodava em modo usuário. Essa é a razão real pela qual o Intel VT-x e o AMD-V adicionaram uma segunda dimensão de privilégio construída especificamente para hypervisors.
Um container compartilha o único kernel do host e obtém a sua visão isolada de processos, interfaces de rede e montagens inteiramente a partir de namespaces, com cgroups limitando os recursos que ele pode consumir. Não há kernel convidado para inicializar, e é exatamente por isso que containers iniciam em milissegundos enquanto uma máquina virtual leva segundos.
Uma lista de controle de acesso anexa a cada objeto a lista exata de sujeitos autorizados a tocá-lo e como: os bits de permissão de leitura/escrita/execução do Unix são uma versão deliberadamente simplificada e de três grupos dessa ideia, e o mecanismo concreto que o SO usa para impor as políticas de autorização já discutidas de forma abstrata em outros lugares.
Em vez de perguntar à ACL de um objeto se um sujeito pode atuar sobre ele, uma capacidade é um bilhete infalsificável que um processo já detém e que prova que ele pode: um modelo genuinamente diferente, real em sistemas como o seL4, que contorna o clássico problema do delegado confuso ao qual um projeto baseado em ACL é propenso.
chroot, seccomp e o descarte de privilégios setuid são todos a mesma ideia real aplicada em granularidades diferentes: dar a um processo em execução o mínimo absoluto de acesso de que ele precisa para fazer o seu trabalho, para que, se ele algum dia for comprometido, o raio de impacto seja pequeno de propósito, e não por sorte.
Acompanhar um único `docker run` desde o fork/exec do shell, passando pela configuração de namespaces e cgroups até a primeira chamada de sistema do processo em sandbox, amarra todos os agrupamentos desta disciplina, e termina com uma comparação honesta e numérica de quanto isolamento um contêiner, uma VM e um processo nu de fato oferecem, e a que custo.
Part of the Computer Science curriculum.
O hardware distingue exatamente dois modos de execução, kernel e usuário, e impõe quais instruções e qual memória cada um pode tocar: o único mecanismo a partir do qual toda outra garantia de proteção no nível do SO desta disciplina é, no fim das contas, construída.
Uma chamada de sistema, uma interrupção de hardware e uma page fault parecem completamente diferentes para o programador, mas a CPU trata as três com exatamente o mesmo mecanismo de trap: salva o estado atual, salta para um ponto de entrada fixo do kernel e deixa o kernel descobrir por que foi chamado.
Rastreando uma única chamada como write() desde um invólucro de biblioteca em espaço de usuário, passando pela instrução de trap, entrando na tabela de chamadas de sistema do kernel, atravessando a rotina real do kernel e voltando: a maquinaria concreta por trás de todo serviço de SO que um programa jamais solicita.
Todo ponteiro e todo tamanho que um programa de usuário entrega a uma chamada de sistema é uma alegação na qual o kernel não pode confiar. O mesmo modo de falha de segurança de memória já visto no nível da aplicação se torna catastrófico aqui, porque o código que confia na entrada ruim está rodando com privilégio total.
O operador | do shell conecta a saída padrão de um processo diretamente à entrada padrão de outro por meio de um buffer de bytes gerenciado pelo kernel: a forma de IPC mais simples, mais antiga e ainda mais comum em qualquer sistema tipo Unix.
O kernel mapeia exatamente a mesma página física em dois espaços de endereçamento que de resto são isolados, dando aos dois processos acesso direto e sem cópia aos mesmos bytes: o mecanismo de IPC mais rápido que existe, e aquele que devolve toda a responsabilidade de sincronização diretamente à mecânica de locks e semáforos já coberta.
Em vez de um buffer compartilhado bruto ou de um fluxo de bytes indiferenciado, o kernel gerencia mensagens discretas e tipadas, com as suas próprias garantias de entrega e ordem. Isso troca a velocidade bruta da memória compartilhada por segurança, já que o kernel media todo acesso em vez de confiar que os processos se coordenem corretamente por conta própria.
A API de sockets de Berkeley apresenta a comunicação com um processo na mesma máquina e com um processo do outro lado do planeta pela exatamente mesma interface de read/write: a abstração para a qual os mecanismos de IPC desta disciplina convergem, e aquela sobre a qual uma futura disciplina de redes constrói diretamente.
Um hypervisor roda um sistema operacional convidado inteiro (kernel, drivers e tudo mais) como se ele tivesse uma máquina inteira só para si, interceptando cada instrução privilegiada que o convidado tenta executar e emulando o seu efeito em vez de deixá-la tocar o hardware real.
O trap-and-emulate sozinho não conseguia virtualizar o conjunto de instruções x86 real, porque um punhado de instruções privilegiadas simplesmente não fazia trap quando rodava em modo usuário. Essa é a razão real pela qual o Intel VT-x e o AMD-V adicionaram uma segunda dimensão de privilégio construída especificamente para hypervisors.
Um container compartilha o único kernel do host e obtém a sua visão isolada de processos, interfaces de rede e montagens inteiramente a partir de namespaces, com cgroups limitando os recursos que ele pode consumir. Não há kernel convidado para inicializar, e é exatamente por isso que containers iniciam em milissegundos enquanto uma máquina virtual leva segundos.
Uma lista de controle de acesso anexa a cada objeto a lista exata de sujeitos autorizados a tocá-lo e como: os bits de permissão de leitura/escrita/execução do Unix são uma versão deliberadamente simplificada e de três grupos dessa ideia, e o mecanismo concreto que o SO usa para impor as políticas de autorização já discutidas de forma abstrata em outros lugares.
Em vez de perguntar à ACL de um objeto se um sujeito pode atuar sobre ele, uma capacidade é um bilhete infalsificável que um processo já detém e que prova que ele pode: um modelo genuinamente diferente, real em sistemas como o seL4, que contorna o clássico problema do delegado confuso ao qual um projeto baseado em ACL é propenso.
chroot, seccomp e o descarte de privilégios setuid são todos a mesma ideia real aplicada em granularidades diferentes: dar a um processo em execução o mínimo absoluto de acesso de que ele precisa para fazer o seu trabalho, para que, se ele algum dia for comprometido, o raio de impacto seja pequeno de propósito, e não por sorte.
Acompanhar um único `docker run` desde o fork/exec do shell, passando pela configuração de namespaces e cgroups até a primeira chamada de sistema do processo em sandbox, amarra todos os agrupamentos desta disciplina, e termina com uma comparação honesta e numérica de quanto isolamento um contêiner, uma VM e um processo nu de fato oferecem, e a que custo.