Hacker News new | past | comments | ask | show | jobs | submit login

You certainly cannot un-unlink file by linking the pseudofile in /proc somewhere, as that would involve cross-filesystem hardlinks.

But it is probably possible to write simple kernel module that would allow you to do that through some non-standard interface.




Yes you can.

    linkat(AT_FDCWD, "/proc/self/fd/N", destdirfd, newname, AT_SYMLINK_FOLLOW);
Will do it. This is the longest-available `flink` syscall method. See https://lwn.net/Articles/562488/

Sadly the AT_EMPTY_PATH change was backed out between 3.11-rc7 and release. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...


As pointed out in another comment, this doesn't work when the link count is 0:

  $ uname -rv
  4.15.0-3-amd64 #1 SMP Debian 4.15.17-1 (2018-04-19)

  $ touch foo

  $ exec 3<>foo

  $ rm foo

  $ ls -l /proc/$$/fd/3
  lrwx------ 1 jwilk jwilk 64 Apr 25 10:02 /proc/324/fd/3 -> '/home/jwilk/foo (deleted)'

  $ strace -e linkat ln -L /proc/$$/fd/3 foo
  linkat(AT_FDCWD, "/proc/3447/fd/3", AT_FDCWD, "foo", AT_SYMLINK_FOLLOW) = -1 ENOENT (No such file or directory)
  ln: failed to create hard link 'foo' => '/proc/3447/fd/3': No such file or directory

  $ sudo strace -e linkat ln -L /proc/$$/fd/3 foo
  linkat(AT_FDCWD, "/proc/3447/fd/3", AT_FDCWD, "foo", AT_SYMLINK_FOLLOW) = -1 ENOENT (No such file or directory)
  ln: failed to create hard link 'foo' => '/proc/3447/fd/3': No such file or directory
  +++ exited with 1 +++


Unless you use `O_TMPFILE` without `O_EXCL` to create the file.

    open("/tmp", O_RDWR|O_TMPFILE, 0666)    = 3
    linkat(3, "", AT_FDCWD, "/tmp/bar", AT_EMPTY_PATH) = 0


I don't think the cross-filesystem hardlink is the problem, since the link in proc is a symbolic link.

I can do this experimentally by creating a symbolic link in /tmp (a different filesystem) to a file in /home, and then creating a hard link (with ln -L) from the symbolic link to another file in /home, and the result is a valid hardlink to the same inode as the original file.

This doesn't work through /proc for an unlinked file, but only because the underlying link call requires a path, not an inode. You can create a hard link out of proc if the file has not been deleted, though, without any cross-filesystem problems.


You have to somehow increment inode's reference count and write reference to it into some directory.

symlink() does not increase reference count of anything and in fact its target does not have to be meaningful filename at all (although in the practical non-POSIX sense there does not exist any string that is not valid filename). One interesting ab-use of this is that you can use symlink()/readlink() as ad-hoc key-value store with atomicity guarantees (that hold true even on NFS). For example emacs uses exactly this for it's file locking mechanism.

IIRC the files in /proc/pid/fd are not true symlinks but something that behaves as both file (you can do same IO operations as on the original FD) and symlink (ie. you can readlink() them and get some string) at once.


man 2 open section about O_TMPFILE seems to strongly imply that you can linkat from /proc/<pid>/fd to concrete file. Not sure if there are some special cases for /proc/self/fd vs /proc/<pid>/fd, but that would seem bit odd.

http://man7.org/linux/man-pages/man2/open.2.html

edit: nevermind, seems like O_TMPFILE is the one that has been special-cased here, from man 2 linkat:

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

http://man7.org/linux/man-pages/man2/linkat.2.html

:(




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: