Bug 240767 - linprocfs(4) - /proc/fd is weird
Summary: linprocfs(4) - /proc/fd is weird
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Only Me
Assignee: Edward Tomasz Napierala
URL:
Keywords:
Depends on:
Blocks: 247219
  Show dependency treegraph
 
Reported: 2019-09-23 12:04 UTC by Edward Tomasz Napierala
Modified: 2020-08-27 23:20 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Edward Tomasz Napierala freebsd_committer 2019-09-23 12:04:52 UTC
Linux apps, such as ps(1), expects stuff in /proc/fd/ to be symlinks.  I'm not sure how to fix it, because I'm not sure how that part of linprocfs actually works - it _somehow_ redirects /proc/fd to /dev/fd/.
Comment 1 Edward Tomasz Napierala freebsd_committer 2020-01-13 12:51:45 UTC
So, the way it works right now is that for current process - and that process only - linprocfs provides a symlink from /proc/self/fd to /dev/fd.

Making this work properly would require adding file descriptor knowledge to procfs itself; possibly to pseudofs.

The current behaviour breaks tty(1) and a recent screen(1).
Comment 2 Edward Tomasz Napierala freebsd_committer 2020-07-03 22:33:56 UTC
Okay, so after another afternoon spent debugging this stuff, here's how it looks:

First, glibc (namely gettyname()) requires contents of /proc/self/fd/ to be symlinks.  Turns out it's trivial to make it work, and it's even documented: just mount fdescfs with 'linrdlnk' option.  I'll make /etc/rc.d/linux default to it soon.

Problem is: it doesn't work when you chroot into your Linux root (eg /compat/linux).  For some reason glibc tries to be very, _very_ careful with the name it got from /proc/self/fd/0; it calls stat(2) on fd 0, and then on the symlink target, and compares st_dev.  When chrooted to /compat/linux, your stdin is on /dev, while /proc/self/fd/0 (really /compat/linux/proc/self/fd/0) points to /dev/fd/0 (really /compat/linux/dev/fd/0); since /dev and /compat/linux/dev have different fsids, and thus stat(2) returns different st_dev, the glibc check fails.

Workaround: run sshd inside your linux chroot and ssh into localhost.  Meh.
Comment 3 Edward Tomasz Napierala freebsd_committer 2020-07-03 22:38:04 UTC
Forgot a crucial point: if anyone has an idea on how to make it work without ssh, please tell.  Using ssh to access your own machine is just silly.  Even though it fixes some other problems with chrooting into linux, eg wrong (for Linux) shell variables.
Comment 4 Edward Tomasz Napierala freebsd_committer 2020-07-03 23:42:15 UTC
https://reviews.freebsd.org/D25559
Comment 5 commit-hook freebsd_committer 2020-07-04 18:01:54 UTC
A commit references this bug:

Author: trasz
Date: Sat Jul  4 18:01:29 UTC 2020
New revision: 362935
URL: https://svnweb.freebsd.org/changeset/base/362935

Log:
  Make the linux rc script use linrdlnk by default.

  This fixes Linux gettyname(3), with caveats (see PR).

  PR:		kern/240767
  MFC after:	2 weeks
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D25558

Changes:
  head/libexec/rc/rc.d/linux
  head/share/man/man4/linux.4
Comment 6 Alexander Leidinger freebsd_committer 2020-07-07 10:51:02 UTC
1. chrooting into /compat/linux is not supposed to work. /compat linux is used by linux_base ports, and linux_base ports are designed for fall-through to FreeBSD config files (where applicable / compatible). The linux-dist ports were used in the past for this, but right now we don't have a linux-dist port.

2. what about redirecting stdin on a cheroot to the fd inside the chroot, does this work? If yes, I would suggest to document it somewhere sensible (linux(4)?).
Comment 7 Edward Tomasz Napierala freebsd_committer 2020-07-08 21:04:42 UTC
1. I know, but for this particular purpose it does (or should) work, since /compat/linux already has its own devfs mount, for /dev/shm/ and /dev/fdescfs/, like any Linux jail would.  And it makes it easy to figure out what's inside that directory.

2. Hm, it could work.  But I eventually figured out how to make it work out of the box, see the kernel patch at https://reviews.freebsd.org/D25559.
Comment 8 commit-hook freebsd_committer 2020-07-11 13:08:30 UTC
A commit references this bug:

Author: trasz
Date: Sat Jul 11 13:08:17 UTC 2020
New revision: 363093
URL: https://svnweb.freebsd.org/changeset/base/363093

Log:
  Make linux stat(2) return the same st_dev for every devfs instance.
  The reason for this is to work around an idiosyncrasy of glibc
  getttynam(3) implementation: it checks whether st_dev returned for
  fd 0 is the same as st_dev returned for the target of /proc/self/fd/0
  symlink, and with linux chroots having their own devfs instance,
  the check will fail if you chrooted into it.

  PR:		kern/240767
  Reviewed by:	kib
  MFC after:	2 weeks
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D25559

Changes:
  head/sys/compat/linux/linux_stats.c
Comment 9 commit-hook freebsd_committer 2020-08-23 22:23:47 UTC
A commit references this bug:

Author: trasz
Date: Sun Aug 23 22:23:19 UTC 2020
New revision: 364572
URL: https://svnweb.freebsd.org/changeset/base/364572

Log:
  MFC r363093:

  Make linux stat(2) return the same st_dev for every devfs instance.
  The reason for this is to work around an idiosyncrasy of glibc
  getttynam(3) implementation: it checks whether st_dev returned for
  fd 0 is the same as st_dev returned for the target of /proc/self/fd/0
  symlink, and with linux chroots having their own devfs instance,
  the check will fail if you chrooted into it.

  PR:		kern/240767
  Sponsored by:	The FreeBSD Foundation

Changes:
_U  stable/12/
  stable/12/sys/compat/linux/linux_stats.c
Comment 10 commit-hook freebsd_committer 2020-08-27 19:43:31 UTC
A commit references this bug:

Author: trasz
Date: Thu Aug 27 19:42:53 UTC 2020
New revision: 364884
URL: https://svnweb.freebsd.org/changeset/base/364884

Log:
  MFC r362935:

  Make the linux rc script use linrdlnk by default.

  This fixes Linux gettyname(3), with caveats (see PR).

  PR:		kern/240767
  Sponsored by:	The FreeBSD Foundation

Changes:
_U  stable/12/
  stable/12/libexec/rc/rc.d/linux
  stable/12/share/man/man4/linux.4