Se eu escrever um programa que tente ler a memória em todos os endereços possíveis e executá-lo em um Unix "cheio", ele não poderá acessar toda a RAM física. Mas como o sistema operacional impede isso?
Eu estou mais familiarizado com pequenas arquiteturas de CPU, onde qualquer parte do código de montagem pode acessar tudo. Não entendo como um programa (o kernel) pode detectar essas operações maliciosas.
Respostas:
Não é o kernel que está impedindo o acesso à memória ruim, é a CPU. O papel do kernel é apenas configurar a CPU corretamente.
Mais precisamente, o componente de hardware que impede o acesso ruim à memória é a MMU . Quando um programa acessa um endereço de memória, o endereço é decodificado pela CPU com base no conteúdo da MMU. A MMU estabelece uma tradução de endereços virtuais para endereços físicos: quando a CPU carrega ou armazena em um determinado endereço virtual, calcula o endereço físico correspondente com base no conteúdo da MMU. O kernel define a configuração do MMU de forma que cada programa possa acessar apenas a memória a que tem direito. Os registros de memória e hardware de outros programas não são mapeados na memória de um programa: esses endereços físicos não têm um endereço virtual correspondente na configuração da MMU para esse programa.
Em uma alternância de contexto entre diferentes processos, o kernel modifica a configuração do MMU para que contenha a tradução desejada para o novo processo.
Alguns endereços virtuais não são mapeados, ou seja, a MMU os converte em um valor especial "sem esse endereço". Quando o processador desreferencia um endereço não mapeado, isso causa uma interceptação: o processador ramifica para um local predefinido no código do kernel. Algumas armadilhas são legítimas; por exemplo, o endereço virtual pode corresponder a uma página que esteja no espaço de troca ; nesse caso, o código do kernel carregará o conteúdo da página da troca e retornará ao programa original de forma que a instrução de acesso à memória seja executada novamente. Outros traps não são legítimos; nesse caso, o processo recebe um sinal que, por padrão, mata o programa imediatamente (e, se não for, ramifica para o manipulador de sinais no programa: em qualquer caso, a instrução de acesso à memória não é concluída).
fonte