écraser cp vs rm puis cp

18

Lorsque j'essaie d'écraser un fichier binaire qui est actuellement lancé, cpne parvient pas à l'écraser, mais il est alors possible de le rmfaire cp. Par exemple:

user@poste:~$ cp binaryFile /tmp
user@poste:~$ sudo cp /tmp/binaryFile binaryFile 
[sudo] password for user:
cp: cannot create regular file `binaryFile`: Text file busy
user@poste:~$ sudo rm binaryFile 
user@poste:~$ sudo cp /tmp/binaryFile  binaryFile 
user@poste:~$ file binaryFile 
binaryFile : ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x7ce005d9eb50e2574246b6a881e625802f7e49f2, not stripped

Une idée pourquoi?

M4rty
la source
2
Petit fil intéressant, mais devrait être sur Unix / Linux.SE IMO.
underscore_d

Réponses:

41

Dans le premier cas, vous essayez de remplacer le contenu d'un fichier en cours d' exécution en tant que programme. Linux ne le permet pas - si c'était le cas, vous écraseriez le code juste au moment où l'OS l'exécutait; la première différence ferait planter le programme ou le rendrait défectueux.

Mais dans le deuxième cas, vous ne modifiez pas réellement le contenu de l'ancien fichier - vous créez un nouveau fichier à sa place, tandis que l'ancien perd simplement le nom de fichier mais conserve son contenu intact.

(N'oubliez rmpas que, techniquement, ne supprime pas les fichiers, il supprime simplement les liens de répertoire - comme pour lnajouter plus de liens au même fichier. Ce n'est que lorsqu'un fichier n'a pas de liens et aucune référence de fichier ouvert, qu'il est automatiquement supprimé.)

Le système fait référence aux fichiers en cours d'utilisation par leur inode, donc peu importe qu'ils aient le même nom de fichier - c'est toujours l' ancien fichier qui reste ouvert par le système, et même s'il n'a plus de liens, il ne sera supprimé une fois tous les programmes fermés.

user1686
la source
7
Une autre astuce qui est souvent utilisée en utilisant la même logique: Ouvrez un fichier (temporaire) dans votre logiciel et supprimez-le immédiatement, sans fermer le fichier au préalable. Votre programme peut toujours l'utiliser comme il le souhaite et lorsque votre programme le ferme (contrôlé) ou oublie de le fermer (par exemple, votre programme s'est écrasé sans nettoyage), il sera automatiquement supprimé par le système d'exploitation. (La fin du programme, peu importe comment cela s'est produit, libère toutes les références au programme dans le fichier.)
Tonny
2
C'est aussi pourquoi lorsque vous supprimez un fichier journal d'un processus en cours d'exécution, la commande df ne renvoie pas la taille corrigée jusqu'à ce que vous arrêtiez le processus
M4rty
Existe-t-il un moyen pour un programme externe (avec des privilèges root) de trouver et de créer un nouveau descripteur pour cet inode pendant? J'imagine qu'il existe des programmes qui utilisent cela comme une «fonction de sécurité», il est donc intéressant de comprendre toute l'histoire.
BenPen
3
@BenPen: Sous Linux, oui - utilisez /proc/*/fdpour y accéder, et éventuellement linkat () pour ajouter un nouveau lien vers le système de fichiers.
user1686
3
@BenPen et grawity: En fait, vous ne pouvez pas lier un inode dans la structure de répertoires s'il n'a aucun lien, même avec linkat(), pour des raisons de sécurité . (Exception à cette règle: sauf si elle a été créée avec open(O_TMPFILE)donc elle a commencé avec zéro lien.) Si vous essayez, linkat()renvoie ENOENT, même en tant que root. Voir ma réponse à cette question pour qu'un script perl s'exécute réellement linkatet prouve qu'il ne fonctionne pas, même en tant que root: /
Peter Cordes