
Lo intenté
xtricman⚓ArchVirtual⏺️~
Respuesta1
Se supone que no puedes hacer eso (pero lee a continuación una excepción interesante).
Si el kernel permitiera que esto sucediera, entonces una llamada como:
fd = open(filename, O_CREAT|O_RDWR, 0666);
unlink(filename);
linkat(fd, "", 0, "/new/path", AT_EMPTY_PATH);
tendría éxito incluso cuando el inodo al que hace referencia fd
tiene un recuento de enlaces de 0, cuando lo realiza un proceso con CAP_DAC_READ_SEARCH
mayúsculas.
Pero el núcleo impide activamente que esto suceda, sin tener en cuenta las capacidades o privilegios del proceso que lo realiza.
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;
Esto también está documentado en la página de manual:
AT_EMPTY_PATH
(desde Linux 2.6.39)Si
oldpath
es una cadena vacía, cree un enlace al archivo al que hace referenciaolddirfd
(que puede haberse obtenido utilizando laopen(2)
O_PATH
bandera). En este caso,olddirfd
puede hacer referencia a cualquier tipo de archivo excepto a un directorio. Por lo general, esto no funcionará si el archivo tiene un recuento de enlaces de cero (los archivos creados conO_TMPFILE
y sinO_EXCL
son una excepción). La persona que llama debe tener laCAP_DAC_READ_SEARCH
capacidad para utilizar este indicador. Esta bandera es específica de Linux; define_GNU_SOURCE
para obtener su definición.
Según la fuente del kernel, no parece haber otra excepción además O_TMPFILE
. O_TMPFILE
está documentado en la open(2)
página de manual; A continuación se muestra un pequeño ejemplo basado en eso:
#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;
}
Respuesta2
Podrías simplemente cat
ese descriptor de archivo:
$ 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
No puedes ln
crear un vínculo físico con ese archivo porque los vínculos físicos no pueden abarcar sistemas de archivos y /proc
son un sistema de archivos virtual ( procfs
), e incluso dentro de /proc
, lo que puedes hacer está restringido (el contenido refleja el estado del núcleo, por lo que no puede realizar operaciones arbitrarias).