o que exatamente isto faz? Eu não entendo como você pode acessar a memória base com isso ... parece meio estranho. É seguro?
dd if=/dev/urandom of=/dev/mem
o que exatamente isto faz? Eu não entendo como você pode acessar a memória base com isso ... parece meio estranho. É seguro?
dd if=/dev/urandom of=/dev/mem
Respostas:
Na verdade, na maioria das plataformas, apenas falha com um erro, mas isso depende da arquitetura do hardware. Definitivamente, não há garantia de que isso seja inofensivo, a menos que você execute o comando como um usuário não privilegiado. Com um usuário sem privilégios, o comando é perfeitamente inofensivo porque você não pode abrir /dev/mem
.
Quando você executa um comando como root, deve saber o que está fazendo. Às vezes , o kernel impede que você faça algo perigoso, mas nem sempre. /dev/mem
é uma daquelas coisas potencialmente perigosas em que você realmente deve saber o que está fazendo.
Vou mostrar como funciona uma gravação /dev/mem
no Linux. O princípio geral seria o mesmo em outros Unices, mas coisas como as opções do kernel são completamente diferentes.
O que acontece quando um processo lê ou grava em um arquivo de dispositivo depende do kernel. Um acesso a um arquivo de dispositivo executa algum código no driver que lida com esse arquivo de dispositivo. Por exemplo, escrever para /dev/mem
invoca a função write_mem
indrivers/char/mem.c
. Essa função recebe 4 argumentos: uma estrutura de dados que representa o arquivo aberto, um ponteiro para os dados a serem gravados, o número de bytes a serem gravados e a posição atual no arquivo.
Observe que você só chega tão longe se o chamador tiver permissão para abrir o arquivo em primeiro lugar. Os arquivos do dispositivo obedecem às permissões de arquivo normalmente. As permissões normais de /dev/mem
são crw-r-----
propriedade de root:kmem
, por isso, se você tentar abri-lo para a escrita sem ser raiz, você só vai obter “permissão negada” (eAccess). Mas se você é root (ou se o root alterou as permissões deste arquivo), a abertura continua e você pode tentar escrever.
O código na write_mem
função faz algumas verificações de integridade, mas essas verificações não são suficientes para proteger contra tudo de ruim. A primeira coisa que faz é converter a posição atual do arquivo *ppos
em um endereço físico. Se isso falhar (na prática, porque você está em uma plataforma com endereços físicos de 32 bits, mas compensa os arquivos de 64 bits e o deslocamento do arquivo é maior que 2 ^ 32), a gravação falha com EFBIG (arquivo muito grande). A próxima verificação é se o intervalo de endereços físicos a serem gravados é válido nessa arquitetura de processador específica e se uma falha resulta em EFAULT (endereço incorreto).
Em seguida, no Sparc e no m68k, qualquer parte da gravação na primeira página física é ignorada silenciosamente.
Chegamos agora ao loop principal que itera os dados em blocos que podem caber em uma página da MMU .
/dev/mem
acessa a memória física, não a memória virtual, mas as instruções do processador para carregar e armazenar dados na memória usam endereços virtuais; portanto, o código precisa organizar o mapeamento da memória física em algum endereço virtual. No Linux, dependendo da arquitetura do processador e da configuração do kernel, esse mapeamento existe permanentemente ou deve ser feito em tempo real; esse é o trabalho de xlate_dev_mem_ptr
(e unxlate_dev_mem_ptr
desfaz o que xlate_dev_mem_ptr
faz). Em seguida, a função copy_from_user
lê do buffer que foi passado para owrite
chamada do sistema e apenas grava no endereço virtual onde a memória física está atualmente mapeada. O código emite instruções normais de armazenamento de memória e o que isso significa depende do hardware.
Antes de discutir o que uma gravação em um endereço físico faz, discutirei uma verificação que ocorre antes dessa gravação. Dentro do loop, os page_is_allowed
blocos de funções acessam determinados endereços se a opção de configuração do kernel CONFIG_STRICT_DEVMEM
estiver ativada (que é o caso por padrão): somente endereços permitidos devmem_is_allowed
podem ser alcançados /dev/mem
; para outros, a gravação falha com EPERM (operação não permitida). A descrição desta opção indica:
Se essa opção estiver ativada e IO_STRICT_DEVMEM = n, o arquivo / dev / mem permitirá apenas o espaço do usuário acessar o espaço PCI e o código do BIOS e as regiões de dados. Isso é suficiente para o dosemu e o X e todos os usuários comuns de / dev / mem.
Esta é uma descrição muito centrada em x86. De fato, mais genericamente, CONFIG_STRICT_DEVMEM
bloqueia o acesso a endereços de memória física que são mapeados para a RAM, mas permite o acesso a endereços que não são mapeados para a RAM. Os detalhes de quais intervalos de endereços físicos são permitidos dependem da arquitetura do processador, mas todos excluem a RAM na qual os dados do kernel e dos processos de terra do usuário são armazenados. A opção adicional CONFIG_IO_STRICT_DEVMEM
(desativada no Ubuntu 18.04) bloqueia o acesso a endereços físicos reivindicados por um driver.
Endereços de memória física que são mapeados para a RAM . Portanto, existem endereços de memória física que não são mapeados para a RAM? Sim. Essa é a discussão que prometi acima sobre o que significa escrever para um endereço.
Uma instrução de armazenamento de memória não necessariamente grava na RAM. O processador decompõe o endereço e decide em qual periférico enviar o armazenamento. (Quando digo "o processador", abro controladores periféricos que podem não ser do mesmo fabricante.) A RAM é apenas um desses periféricos. O modo como o envio é feito depende muito da arquitetura do processador, mas os fundamentos são mais ou menos os mesmos em todas as arquiteturas. O processador basicamente decompõe os bits mais altos do endereço e os pesquisa em algumas tabelas que são preenchidas com base em informações codificadas, informações obtidas pela sondagem de alguns barramentos e informações configuradas pelo software. Muito cache e buffer podem estar envolvidos, mas, em poucas palavras, após essa decomposição,ônibus e então cabe ao periférico lidar com isso. (Ou o resultado da pesquisa de tabela pode ser que não há periférico nesse endereço; nesse caso, o processador entra em um estado de trap onde executa algum código no kernel que normalmente resulta em um SIGBUS para o processo de chamada.)
Um armazenamento em um endereço que mapeia para a RAM não "substitui" o valor que foi anteriormente armazenado nesse endereço, com a promessa de que uma carga posterior no mesmo endereço retornará o último valor armazenado. Mas mesmo a RAM possui alguns endereços que não se comportam dessa maneira: possui alguns registros que podem controlar coisas como taxa de atualização e voltagem.
Em geral, uma leitura ou gravação em um registro de hardware faz o que o hardware está programado para fazer. A maioria dos acessos ao hardware funciona da seguinte maneira: o software (normalmente código do kernel) acessa um determinado endereço físico, atinge o barramento que conecta o processador ao periférico, e o periférico faz o seu trabalho. Alguns processadores (em particular o x86) também possuem instruções de CPU separadas que causam leituras / gravações em periféricos distintos do carregamento e armazenamento de memória, mas mesmo no x86, muitos periféricos são alcançados através do carregamento / armazenamento.
O comando dd if=/dev/urandom of=/dev/mem
grava dados aleatórios em qualquer periférico mapeado no endereço 0 (e nos endereços subsequentes, desde que as gravações sejam bem-sucedidas). Na prática, espero que em muitas arquiteturas, o endereço físico 0 não tenha nenhum periférico mapeado para ele ou tenha RAM e, portanto, a primeira tentativa de gravação falhe. Mas se houver um periférico mapeado no endereço 0, ou se você alterar o comando para gravar em um endereço diferente, acionará algo imprevisível no periférico. Com dados aleatórios em endereços crescentes, é improvável que faça algo interessante, mas, em princípio, ele pode desligar o computador (provavelmente há um endereço que faça isso de fato), substituir algumas configurações da BIOS que impossibilitem a inicialização ou até atingir algumas periférico de buggy de uma maneira que o danifique.
alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
CONFIG_STRICT_DEVMEM
estiver ativado.
Por página de manual mem (4) :
/ dev / mem é um arquivo de dispositivo de caractere que é uma imagem da memória principal do computador. Pode ser usado, por exemplo, para examinar (e até corrigir) o sistema.
Portanto, em teoria, você dd if=/dev/urandom of=/dev/mem
deve substituir todo o espaço de endereço da memória física que você instalou e, como o kernel e outros programas são executados a partir da memória, isso deve travar o sistema. Na prática, há limite. Na mesma página do manual:
Desde o Linux 2.6.26, e dependendo da arquitetura, a opção de configuração do kernel CONFIG_STRICT_DEVMEM limita as áreas que podem ser acessadas por esse arquivo.
Tentando isso na máquina virtual Ubuntu 18.04, ele retorna um erro dd: writing to '/dev/mem': Operation not permitted
mesmo com sudo
e apesar das permissões para root crw-r-----
. Do Ubuntu Wiki :
/ dev / proteção de mem
Alguns aplicativos (Xorg) precisam de acesso direto à memória física a partir do espaço do usuário. O arquivo especial / dev / mem existe para fornecer esse acesso. No passado, era possível visualizar e alterar a memória do kernel desse arquivo se um invasor tivesse acesso root. A opção do kernel CONFIG_STRICT_DEVMEM foi introduzida para bloquear o acesso à memória que não é do dispositivo (originalmente chamado CONFIG_NONPROMISC_DEVMEM).
Então, tecnicamente, não, não é seguro (já que travaria o sistema) e se a opção do kernel CONFIG_STRICT_DEVMEM
estiver desativada, isso é uma falha de segurança, mas pelo que vejo até agora, o comando não funcionaria se essa opção estiver ativada. De acordo com a duplicação entre sites , uma reinicialização corrigirá quaisquer problemas com ela, mas é claro que os dados na RAM naquele momento seriam perdidos e não liberados para o disco (se necessário).
Há um método sugerido no duplicado vinculado anteriormente, busybox devmem
portanto, se você estiver determinado a mexer com a RAM, pode haver uma maneira, afinal.
CONFIG_STRICT_DEVMEM
, você pode acessar regiões de memória onde um periférico é mapeado, que é o ponto principal de se ter /dev/mem
. Se você escreve coisas aleatórias em periféricos, tudo pode acontecer. Você obtém "operação não permitida" se tentar acessar um endereço que não está mapeado e o comando inicia no endereço 0. Se o endereço 0 é mapeado para algo ruim, depende da arquitetura do hardware. Pelo que sei, ele pode nunca ser mapeado para qualquer coisa em um PC, mas não é seguro em geral.
head -c 1024 </dev/mem | od -tx1
), mas não sei se eles são usados quando o processador não está no modo real (modo 8088). Eu não acho que eles possam ser usados no modo de 64 bits: afinal, os vetores de interrupção 8088 têm apenas 32 bits para o endereço. E pela maneira como isso é acessível com o CONFIG_STRICT_DEVMEM
set, acho que o Linux não o usa.