
Ich habe es versucht
xtricman⚓ArchVirtual⏺️~
Antwort1
Eigentlich sollten Sie dazu nicht in der Lage sein (lesen Sie jedoch weiter unten, um mehr über eine interessante Ausnahme zu erfahren).
Wenn der Kernel dies zulassen würde, würde ein Aufruf wie dieser ausreichen:
fd = open(filename, O_CREAT|O_RDWR, 0666);
unlink(filename);
linkat(fd, "", 0, "/new/path", AT_EMPTY_PATH);
wäre erfolgreich, selbst wenn der von referenzierte Inode fd
eine Linkanzahl von 0 hätte, wenn dies von einem Prozess mit CAP_DAC_READ_SEARCH
Caps durchgeführt wird.
Der Kernel verhindert dies jedoch aktiv, ohne Rücksicht auf die Fähigkeiten oder Privilegien des ausführenden Prozesses.
int vfs_link(struct dentry *old_dentry, ...
{
...
/* Make sure we don't allow creating hardlink to an unlinked file */
if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
error = -ENOENT;
Dies ist auch in der Manpage dokumentiert:
AT_EMPTY_PATH
(seit Linux 2.6.39)Wenn
oldpath
es sich um eine leere Zeichenfolge handelt, erstellen Sie einen Link zu der Datei, auf die verwiesen wirdolddirfd
(die möglicherweise mithilfe des Flags abgerufen wurdeopen(2)
O_PATH
). In diesem Fallolddirfd
kann auf jeden Dateityp außer einem Verzeichnis verwiesen werden. Dies funktioniert im Allgemeinen nicht, wenn die Datei eine Linkanzahl von Null hat (Dateien, die mitO_TMPFILE
und ohne erstellt wurden,O_EXCL
sind eine Ausnahme).. Der Anrufer muss dieCAP_DAC_READ_SEARCH
Berechtigung haben, dieses Flag zu verwenden. Dieses Flag ist Linux-spezifisch; definieren Sie,_GNU_SOURCE
um seine Definition zu erhalten.
basierend auf dem Kernel-Quellcode scheint es außer keine andere Ausnahme zu geben O_TMPFILE
. O_TMPFILE
ist in der open(2)
Manpage dokumentiert; unten ist ein kleines Beispiel, das darauf basiert:
#define _GNU_SOURCE 1
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <err.h>
int main(int ac, char **av){
char path[64]; int fd;
if(ac < 3) errx(1, "usage: %s dir newpath", av[0]);
if((fd = open(av[1], O_TMPFILE|O_RDWR, 0666)) == -1) err(1, "open");
/*
* ...
* write stuff to fd and only "realize" the file at the end if
* everything has succeeded
*/
/* the following line only works with CAP_DAC_READ_SEARCH */
/* if(linkat(fd, "", 0, av[2], AT_EMPTY_PATH)) err(1, "linkat"); */
snprintf(path, sizeof path, "/proc/self/fd/%d", fd);
if(linkat(AT_FDCWD, path, AT_FDCWD, av[2], AT_SYMLINK_FOLLOW))
err(1, "linkat");
return 0;
}
Antwort2
Sie könnten einfach cat
diesen Dateideskriptor verwenden:
$ echo foo > bar
$ sleep 10m < bar & rm bar
[1] 15743
$ ls -l /proc/15743/fd
total 0
lr-x------ 1 olorin olorin 64 Jan 16 17:49 0 -> /tmp/bar (deleted)
lrwx------ 1 olorin olorin 64 Jan 16 17:49 1 -> /dev/pts/6
lrwx------ 1 olorin olorin 64 Jan 16 17:49 2 -> /dev/pts/6
$ cat /proc/15743/fd/0
foo
$ cat /proc/15743/fd/0 > bar
$ cat bar
foo
Sie können ln
für diese Datei keinen Hardlink erstellen, da sich Hardlinks nicht über Dateisysteme erstrecken können und /proc
es sich um ein virtuelles Dateisystem ( procfs
) handelt und /proc
Ihre Möglichkeiten sogar innerhalb von eingeschränkt sind (der Inhalt spiegelt den Zustand des Kernels wider, daher können Sie keine beliebigen Operationen durchführen).