web-dev-qa-db-fra.com

Vi peut écrire dans un fichier alors que le fichier est en lecture seule.

L'exemple suivant montre comment créer un fichier avec uniquement des autorisations de lecture. Comme nous pouvons le constater, lorsque j'essaie d'écrire dans ce fichier à l'aide de la commande echo, Permission denied,.

Mais pourquoi, dans le cas où nous utilisons vi, obtenons-nous pas Permission denied? Comme on peut le voir ici, nous pouvons écrire dans le fichier même s'il est en lecture seule.

Que se passe-t-il ici? Est-ce un bug de 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
12
maihabunash

Note : Pour des raisons de licence, la plupart des distributions GNU/Linux n'incluent pas le programme vi d'origine écrit par Bill Joy. Au lieu de cela, la commande vi est fournie en exécutant Vim en mode de compatibilité vi. La réponse suivante est basée sur l'exécution de Vim avec son mode de compatibilité vi.

Modification d'un fichier en lecture seule

Vim avertit l'utilisateur s'il modifie le tampon d'un fichier en lecture seule, W10: Warning: Changing a readonly file. Si l'utilisateur tente d'écrire dans ce fichier, il reçoit le message d'erreur suivant, 'readonly' option is set (add ! to override).

Lorsque le répertoire parent est accessible en écriture à l'utilisateur Vim

Vim, étant utile, indique à l'utilisateur qu'il peut forcer l'écriture en ajoutant un point d'exclamation, !, à la commande w. Si cette version percutante de la commande write est utilisée, Vim supprime le fichier d'origine (si vous utilisez Vim avec l'ensemble d'options Vim-only backup, le fichier d'origine est en réalité renommé identique au fichier de sauvegarde). Il ouvre ensuite (crée) un nouveau fichier avec le même nom que l'original et écrit le contenu de sa mémoire tampon dans ce nouveau fichier. Ceci peut être observé en vérifiant le inode du fichier avant et après l'exécution de 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

Remarque: Cela peut également modifier l'autorisation et la propriété du fichier ainsi que les liens (symboliques), par exemple, si le fichier d'origine appartenait à un autre utilisateur, le nouveau fichier appartiendrait à l'utilisateur exécutant Vim.

Un processus ne peut le faire que s’il dispose des droits en écriture sur le répertoire parent du fichier. En général, pour vous assurer qu'un programme ne puisse pas modifier un fichier, les autorisations du fichier lui-même et de son répertoire parent doivent être sécurisées.

Lorsque le répertoire parent n'est pas accessible en écriture à l'utilisateur Vim

Cependant, même dans ce cas, Vim s'efforce toujours d'aider l'utilisateur persistant à écraser le fichier. Si l'utilisateur Vim est propriétaire du fichier, Vim peut contourner la restriction du répertoire parent en lecture seule en modifiant temporairement l'autorisation du fichier (à l'aide de l'appel système chmod), en écrivant le tampon dans le fichier, en fermant le fichier, puis en modifiant les autorisations en arrière. Voici un extrait des appels système effectués lors de l'exécution de vi par 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

Remarque: cela ne se produit pas si l'utilisateur Vim est en train de modifier un fichier dont il n'est pas propriétaire, car Vim ne pourra pas modifier les autorisations de fichier.

Addenda

Pour être vraiment certain qu’un fichier ne peut pas être modifié (sur un système GNU/Linux), exécutez la commande chattr en tant que superutilisateur:

Sudo chattr +i filename

De man chattr:

Un fichier avec l’attribut "i" ne peut pas être modifié: il ne peut pas être supprimé ou renommé, aucun lien ne peut être créé avec ce fichier et aucune donnée ne peut être écrite dans ce fichier. Seul le superutilisateur ou un processus possédant la capacité CAP_LINUX_IMMUTABLE peut définir ou effacer cet attribut.

27
Anthony Geoghegan

La plupart sinon toutes les implémentations de vi vous empêchent d’écrire le fichier si vous utilisez une commande de sauvegarde régulière telle que ZZ, :w, :wq ou :x, par exemple avec vim:

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

D'autre part, si vous indiquez à vi d'écrire le fichier malgré ses autorisations, en utilisant quelque chose comme :x! ou :wq!, l'éditeur assouplit temporairement les autorisations pour permettre l'écriture du fichier:

...
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
....

Dans ce cas, le numéro d'inode reste inchangé.

Enfin, il ne s’agit pas d’un bogue, car si vous n’êtes pas autorisé à modifier les autorisations de fichiers, vous ne pouvez pas le modifier via vi.

5
jlliagre