4

I tried

xtricman⚓ArchVirtual⏺️~🤐ls /proc/self/fd/ -l
Total 0
lrwx------ 1 xtricman users 64 1月  16 16:34 0 -> /dev/pts/0
lrwx------ 1 xtricman users 64 1月  16 16:34 1 -> /dev/pts/0
lrwx------ 1 xtricman users 64 1月  16 16:34 2 -> /dev/pts/0
lrwx------ 1 xtricman users 64 1月  16 16:34 3 -> '/home/xtricman/a (deleted)'
lr-x------ 1 xtricman users 64 1月  16 16:34 4 -> /proc/1273/fd
xtricman⚓ArchVirtual⏺️~🤐ln /proc/self/fd/3 b
ln: failed to create hard link 'b' => '/proc/self/fd/3': Invalid cross-device link

Since the inode is still on the disk, how can I re-create a name for it? What if there's no open file description pointing to that inode but that inode is mmaped? How can I restore it in that case?

1
  • 2
    basically the same question as: unix.stackexchange.com/questions/92816/… tl;dr; you can't without hacks. read the lkml links from the answers there -- I don't think anything has changed since then.
    – user313992
    Jan 16, 2019 at 12:53

2 Answers 2

7

You're not supposed to be able to do that (but read below for an interesting exception).

If the kernel was to let it happen, then a call like:

fd = open(filename, O_CREAT|O_RDWR, 0666);
unlink(filename);

linkat(fd, "", 0, "/new/path", AT_EMPTY_PATH);

would succeed even when the inode referenced by fd has a link count of 0, when done by a process with CAP_DAC_READ_SEARCH caps.

But the kernel is actively preventing it from happening, without regard to the capabilities or privileges of the process doing it.

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;

This is also documented in the manpage:

AT_EMPTY_PATH (since Linux 2.6.39)

If oldpath is an empty string, create a link to the file referenced by olddirfd (which may have been obtained using the open(2) O_PATH flag). In this case, olddirfd can refer to any type of file except a directory. This will generally not work if the file has a link count of zero (files created with O_TMPFILE and without O_EXCL are an exception). The caller must have the CAP_DAC_READ_SEARCH capability in order to use this flag. This flag is Linux-specific; define _GNU_SOURCE to obtain its definition.

based on the kernel source, there seems to be no other exception besides O_TMPFILE. O_TMPFILE is documented in the open(2) manpage; below is a small example based on that:

#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;
}
3

You could simply cat that file descriptor:

$ 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

You can't ln that file to make a hard link because hard links can't span filesystems, and /proc is a virtual filesystem (procfs), and even within /proc, what you can do is restricted (the contents reflect the state of the kernel, so you can't perform arbitrary operations).

2
  • But I want to restore the inode, not just duplicate the data. Jan 16, 2019 at 10:33
  • 2
    That's not going to be possible without hackery. Even tools which "undelete" files don't restore to the same inode.
    – Olorin
    Jan 17, 2019 at 1:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .