Vim pode quebrar permissões de arquivo?

8

Eu estava usando o Vim outro dia, como de costume, quando notei algo estranho. Aqui está o que eu fiz:

~$ touch testfile
~$ ls -l | grep testfile
-rw-r--r-- 1 username groupname 0 Jul 23 10:00 testfile
~$ vim testfile

Então fiz uma alteração, salvei e saí com :wq. Bastante normal. Então, no entanto:

~$ sudo chown root:root testfile
~$ sudo chmod 644 testfile
~$ sudo -k
~$ ls -l | grep testfile
-rw-r--r-- root root 0 Jul 23 10:02 testfile
~$ vim testfile

Portanto, o root deve ter acesso r / w e todo mundo deve ter lido apenas. Edite o arquivo, tente salvar - você não pode. Incrível, funcionando como pretendido. No entanto, se você salvar com :w!, o vim alterará de alguma forma a propriedade do arquivo de volta para nome de usuário: usergroup e o arquivo será salvo. Mesmo se você fizer isso:

~$ sudo chmod 444 testfile
~$ sudo -k
~$ ls -l | grep testfile
-r--r--r-- 1 root root 0 Jul 23 10:06 testfile
~$ vim testfile

Você ainda pode substituir com :w!! O que está acontecendo? Como o vim pode violar as leis de propriedade e permissão de arquivos assim? Olhei para a página de ajuda no vim dizendo :help :we encontrei o seguinte:

:w[rite]! [++opt]    Like ":write", but forcefully write when 'readonly' is set or there is another reason why writing was refused.
                     Note: This may change the permission and ownership of the file and break (symbolic) links. Add the 'W' flage to 'cpoptions' to avoid this.

Eu não consegui gravar em um arquivo no vim anteriormente quando não deveria, então acho que o verdadeiro cerne da minha pergunta é: como posso tornar um arquivo não-editável pelo vim e por que não é baseado em arquivo permissões de sistema, como eu esperaria, e qual mecanismo o vim está usando para editar o arquivo que outros editores (gedit, nano) não podem usar?

EDIT: O computador em que tentei usar o kernel do Linux 3.15.5-2-ARCH. O número da versão do Vim é 7.4.373-1 e é o instalado por pacman- eu não o compilei do zero com nenhuma opção especial.

zrneely
fonte
Eu não parecem ser capazes de reproduzir o problema, a menos que tomar alguns truques como descrito aqui
Davyzhu
Eu apenas tentei novamente usando os comandos da pergunta e aconteceu da mesma maneira. Editarei a pergunta para adicionar detalhes sobre o meu computador, pois parece que isso pode depender da plataforma.
Zrneely
Meu primeiro palpite é que você pode alterar a propriedade dos arquivos em um diretório ao qual tem acesso de gravação. Mas parece que não é esse o caso . CAP_CHOWNé necessário ligar chown(2). A propósito, eu posso reproduzir no Debian, com o vim 7.4.
23414 Bob

Respostas:

10

Percebo que seu caminho atual é ~o diretório inicial do usuário. Você deve ter permissões de gravação nesse diretório.

Pense de outra maneira - se você tem permissões de leitura e gravação no diretório, o que impede você de copiar o arquivo, excluir o antigo e renomear o novo com permissões diferentes?

É exatamente isso que o vim faz!


Se você executar o vim sob strace, por exemplo:

open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0644) = -1 EACCES (Permission denied)
lstat("testfile", {st_mode=S_IFREG|0644, st_size=10, ...}) = 0
getuid()                                = 1000
unlink("testfile")                      = 0
open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 3
write(3, "ffjidfjds\n", 10)             = 10
fsync(3)                                = 0
close(3)                                = 0
chmod("testfile", 0644)                 = 0

Com base nesse log, posso adivinhar o seguinte processo:

Algumas verificações de permissão anteriores (e chowntentativas, etc.) são omitidas por questões de brevidade.

  1. open Tentativa de abrir o arquivo para gravação (falha: permissão negada)
  2. lstat Verifique o proprietário do arquivo
  3. getuuid Verifique o ID do usuário atual para ver se eles correspondem ao proprietário do arquivo
  4. unlink Exclua o arquivo (isso é permitido porque a permissão de gravação no diretório)
  5. open Crie um novo arquivo com o mesmo nome
  6. write O conteúdo do arquivo (leia mais cedo, eu digitei algumas semelhanças)
  7. fsync Liberar o arquivo no disco (não é realmente importante)
  8. close
  9. chmod Altere as permissões do novo arquivo para se parecer com o antigo - acontece agora de ter um novo proprietário.
Prumo
fonte
Ok obrigado. Estou feliz por ter resolvido isso. Portanto, se eu não tiver permissões de gravação no diretório, não poderei usá-lo :w!, o que faz sentido.
Zrneely
Além disso, as informações de rastreamento são realmente úteis - agora eu tenho outra ferramenta para minhas próprias investigações no futuro.
23414 zrneely
1
@zrneely Uma dica para strace: use a -oopção para gravar a saída em um arquivo; caso contrário, entrará em conflito com vima saída. Quanto permissões de gravação, eu não vê-lo verificar as permissões de diretório com statmas não tentar criar um arquivo (chamado 4913, parece aleatório) no diretório atual e, em seguida, excluí-lo.
23414 Bob
Parece que, 4913na verdade, é apenas o primeiro nome que ele tenta e seu objetivo é verificar se ele possui permissões suficientes para isso. Veja: bugzilla.redhat.com/show_bug.cgi?id=427711#c6 and groups.google.com/forum/#!topic/vim_dev/sppdpElxY44
Bob