O Vi pode gravar no arquivo, apesar do arquivo ser somente leitura

12

O exemplo a seguir mostra como criar um arquivo com apenas permissões de leitura. Como podemos ver, quando tento gravar neste arquivo usando o comando echo que recebo Permission denied,.

Mas por que, no caso de usarmos vi, não conseguimos Permission denied? Como pode ser visto aqui, podemos gravar no arquivo, mesmo que o arquivo seja somente leitura.

O que esta acontecendo aqui? Isso é um bug do vi?

[admin@madona-machine1 ~]$ touch test-file
[admin@madona-machine1 ~]$ ls -ltr
total 0
-rw-r--r-- 1 admin admin 0 Apr 13 07:32 test-file
[admin@madona-machine1 ~]$ chmod -w  test-file
[admin@madona-machine1 ~]$ ls -ltr
total 0
-r--r--r-- 1 admin admin 0 Apr 13 07:32 test-file
[admin@madona-machine1 ~]$ echo try_to_write > test-file
-bash: test-file: Permission denied
[admin@madona-machine1 ~]$ vi test-file

I am good singer,

 ~
 ~
 ~
 ~
 ~
 ~
 ~                                                
   "test-file" 1L, 4C written
maihabunash
fonte
1
Para sua informação, existe um site beta SE para isso - vi.stackexchange.com
Raystafarian 13/15

Respostas:

28

Nota : Devido a razões de licenciamento herdadas, a maioria das distribuições GNU / Linux não inclui o programa vi original, conforme escrito por Bill Joy. Em vez disso, o comando vi é fornecido executando o Vim no modo de compatibilidade com vi. A resposta a seguir é baseada na execução do Vim com seu modo de compatibilidade com o vi.

Modificando um arquivo somente leitura

O Vim avisa o usuário se ele modificar o buffer de um arquivo somente leitura W10: Warning: Changing a readonly file,. Se o usuário tenta escrever para esse arquivo, eles recebem a seguinte mensagem de erro, 'readonly' option is set (add ! to override).

Quando o diretório pai é gravável pelo usuário do Vim

O Vim, sendo útil, permite que o usuário saiba que ele pode insistir forçosamente na gravação anexando um ponto de exclamação !ao wcomando. Se esta versão vigorosa do comando write for usada, o Vim excluirá o arquivo original (se estiver usando o Vim com a backupopção somente Vim configurada, o arquivo original será renomeado para ser o mesmo que o arquivo de backup). Em seguida, ele abre (cria) um novo arquivo com o mesmo nome que o original e grava o conteúdo de seu buffer nesse novo arquivo. Isso pode ser observado verificando o inode do arquivo antes e depois da execução do Vim:

$ ls -l --inode t

131529 -r--r--r-- 1 anthony anthony 0 Apr 13 09:23 t

$ vi t
$ ls -l --inode t

131649 -r--r--r-- 1 anthony anthony 4 Apr 13 09:23 t

Nota: Isso também pode alterar a permissão e a propriedade do arquivo e quebrar os links (simbólicos), por exemplo, se o arquivo original pertencer a outro usuário, o novo arquivo pertencerá ao usuário que executa o Vim.

Um processo só pode fazer isso se tiver permissão de gravação para o diretório pai do arquivo. Em geral, para garantir que um programa não possa modificar um arquivo, as permissões do próprio arquivo e de seu diretório pai devem ser protegidas.

Quando o diretório pai não é gravável pelo usuário do Vim

No entanto, mesmo nesse caso, o Vim ainda faz o possível para ajudar o usuário insistente a sobrescrever o arquivo. Se o usuário do Vim tiver a propriedade do arquivo, o Vim poderá contornar a restrição de diretório pai somente leitura alterando temporariamente a permissão do arquivo (usando a chmodchamada do sistema), gravando o buffer no arquivo, fechando o arquivo e, em seguida, alterando o permissões de volta. Aqui está um extrato das chamadas do sistema feitas durante a execução do vi através do strace strace -o ../vi.trace vi t:

getuid()                                = 501
chmod("t", 0100644)                     = 0
open("t", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 4
write(4, "I am good singer,\n", 18)     = 18
fsync(4)                                = 0
close(4)                                = 0
chmod("t", 0100444)                     = 0

Nota: Isso não acontece se o usuário do Vim estiver editando um arquivo do qual não possui propriedade, pois o Vim não poderá alterar as permissões do arquivo.

Termo aditivo

Para ter certeza de que um arquivo não pode ser modificado (em um sistema GNU / Linux), execute o chattrcomando como superusuário:

sudo chattr +i filename

De man chattr:

Um arquivo com o atributo 'i' não pode ser modificado: não pode ser excluído ou renomeado, nenhum link pode ser criado para esse arquivo e nenhum dado pode ser gravado no arquivo. Somente o superusuário ou um processo que possui o recurso CAP_LINUX_IMMUTABLE pode definir ou limpar esse atributo.

Anthony Geoghegan
fonte
2
Santo fumo, isso foi completo!
Camille Goudeseune 13/04
4
@CamilleGoudeseune Depois de postar a primeira versão da minha resposta, fiz alguns experimentos e acabei gastando cerca de uma hora executando o Vim através do strace para ver o que estava fazendo nos bastidores em diferentes situações (diferentes permutações de permissões e propriedade de ambos os arquivos e Diretório Parental). Às vezes me empolgo, mas depois de publicar uma resposta, queria ter certeza de que o que estava dizendo estava correto.
Anthony Geoghegan
5

A maioria, se não todas as viimplementações impedi-lo para gravar o arquivo se você usar um regular comando Salvar como quer ZZ, :w, :wqou :x, por exemplo, com vim:

:w
E45: 'readonly' option is set (add ! to override)

Por outro lado, se você pedir vipara gravar o arquivo apesar de suas permissões, usando algo como :x!ou :wq!, o editor estará relaxando temporariamente as permissões para permitir que o arquivo seja gravado:

...
stat("test-file", {st_mode=S_IFREG|0444, st_size=7, ...}) = 0
getuid()                                = 1000
chmod("test-file", 0100644)             = 0
...
open("test-file", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 4
write(4, "I am good singer,\n", 18)               = 18
fsync(4)                                = 0
close(4)                                = 0
chmod("test-file", 0100444)             = 0
....

Nesse caso, o número do inode permanece inalterado.

Finalmente, isso não é um bug, como se você não tivesse permissão para alterar as permissões do arquivo, não poderá modificá-lo completamente vi.

jlliagre
fonte
Hah! Depois de postar minha resposta, fiz alguns experimentos e acabei passando quase uma hora executando o Vim através do strace para ver o que estava fazendo nos bastidores em diferentes situações (permutações diferentes de permissões e propriedade do arquivo e do diretório pai). Acabei de ver sua resposta depois que terminei de resumir os resultados de minhas experiências. Foi uma boa experiencia de aprendizado.
Anthony Geoghegan