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/.
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).
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.
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.
A commit references this bug:
Date: Sat Jul 4 18:01:29 UTC 2020
New revision: 362935
Make the linux rc script use linrdlnk by default.
This fixes Linux gettyname(3), with caveats (see PR).
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D25558
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)?).
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.