Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

file searches fail when procfs is mounted at multiple mount points #185

Open
DamjanJovanovic opened this issue Dec 19, 2021 · 0 comments
Open

Comments

@DamjanJovanovic
Copy link
Contributor

With HASPROCFS enabled, and procfs mounted in multiple places (eg. main system and a nested chroot), "lsof /proc/1/map" can fail to find anything, even though "lsof | grep /proc/1/map" works.

On multiple dialects (du, freebsd, n+obsd, sun, uw; Linux might be unaffected), the following seems to happen. There is a general filename search code path (running through multiple files), and a procfs-specific code path. The choice between them begins in dmnt.c: it populates Mtprocfs if exactly one procfs mountpoint is found to activate the procfs-specific code path, otherwise it is set to NULL to fall back to the general code path. Then in arg.c that populates other variables.

Later in dnode.c, at the bottom of process_node(), if Ntype == N_PROC, the procfs-specific search takes place. If Mtprocfs was set then Procfsid will be set, and custom logic compares pids and inodes. If multiple procfs mountpoints existed, Mtprocfs wouldn't have been set, Procfsid is NULL, and nothing will ever match.

Even hacking around that, to make procfs files go through the general path (the Ntype != N_PROC case), it still fails to match. This is because is_file_named() requires a match on both dev and inode, and earlier in process_node(), N_PROC files have this run on them:

Lf->dev_def= Lf->rdev_def = 0;

causing is_file_named() to also never match.

Both issues should be fixed. If multiple procfs mounts should fall back to the general case, then it should fall back properly: the condition shouldn't be if (Ntype == N_PROC) but rather something like if (Ntype == N_PROC && Procfsid). Then either the dev on procfs should be treated as valid (with dev_def=1) (on FreeBSD it is valid and differs between mountpoints), or is_file_named() should have a custom search mode purely for procfs inodes that ignores dev.

(I also don't understand why we have the procfs-specific search path in the first place.)

I'll try fix to this in FreeBSD's dnode.c, but other dialects are beyond me.

DamjanJovanovic added a commit to DamjanJovanovic/lsof that referenced this issue Dec 19, 2021
DamjanJovanovic added a commit to DamjanJovanovic/lsof that referenced this issue Jun 23, 2022
lrosenman pushed a commit that referenced this issue Sep 16, 2022
* [FreeBSD] use the kern.proc.proc/kern.proc.all sysctls
instead of kvm_getprocs() to list process.

* [FreeBSD] allow kvm_open() to fail, make kread() also fail afterwards.

* [FreeBSD] Read the system-wide file table (kern.file sysctl) for later use.

* [FreeBSD] link to libutil, and use its kinfo_getfile() function to retrieve
file descriptors, which will be processed, for now, exactly like before.

* [FreeBSD] Start using the libutil-based process_file_descriptors() function.
Remove the old code. This finally gets lsof working without root access,
but it won't show much details about the files yet as it still uses kvm
access to get them.

* [FreeBSD] implement process_kinfo_file(), our own version of the lib/prfd.c
process_file() function, but do it using "struct kinfo_file" and
"struct xfile", giving us the freedom to incrementally change processing
per file type to not use kvm, unlike the process_file() function which
forces the functions it calls to use kvm.

* [FreeBSD] implement pipes using "struct kinfo_file", falling back to kvm
where possible for missing functionality.

* [FreeBSD] implement ptys using "struct kinfo_file" exclusively.

* [FreeBSD] add some functions for reading socket PCBs for future use.

* [FreeBSD] implement sockets using only kinfo_file and PCBs.
Undefine USE_LIB_PROCESS_FILE since it can't link any more.
Remove INRIA-specific IPv6 code as it died out decades ago.

* [FreeBSD] read "struct xvnode" list for future use.

* [FreeBSD] begin converting process_node() to usermode data only.

Rename process_node() to process_vnode() as the former is declared
for all dialects and can't be changed.

Reimplement readvfs() using the statfs() call (whose prototype had
to be re-declared as the _KERNEL define hides it and other things break
without it). Also add the ability to search for filesystems by filename,
which also helps as KERN_VNODE is completely broken.

Use the system-wide xvnode array to find the matching xvnode for
each xfile, and pass it to process_node(). There, make reading the
kernel "struct vnode" optional for now, and start using kinfo_file,
xfile and xvnode fields in favour of the kernel's "struct vnode".

* [FreeBSD] initialize the uninitialized socket and PCB pointers.

* [FreeBSD] use get_lock_state() on all possible filesystems, not just UFS and ZFS.

* [FreeBSD] obtain the inode number from kinfo_file instead of the kernel.

* [FreeBSD] use kinfo_file's vnode type instead of vnode's which
may be absent.

* [FreeBSD] use kinfo_file's dev and rdev instead of filesystems'.

* [FreeBSD] obtain the file size using kinfo_file only.

* [FreeBSD] get the link count using a stat() call.

* [FreeBSD] kernel filesystem-specific data was used to extract
the dev, inode, link count and size. Since we get those from
userspace data now, we no longer need that code. Begin by removing
msdosfs, cd9660 and fusefs specific code.

* [FreeBSD] we don't need ZFS-specific code either.

* [FreeBSD] no need for NFS-specific code.

* [FreeBSD] no fdescfs-specific code is necessary either.

* [FreeBSD] remove pseudofs-specific code too.

* [FreeBSD] no more tmpfs-specific code.

* [FreeBSD] remove the devfs-specific code.

* [FreeBSD] no more UFS-specific code.

* [FreeBSD] remove some device related unused variables.

* [FreeBSD] remove other unused variables.

* [FreeBSD] Dev2Udev() is done by the kernel, we don't need it.

* [FreeBSD] remove vtags. We only have 2 filesystems needing
special cases, and they are easier to check with an if statement.
Also it should no longer be an error to have an unknown filesystem.

* [FreeBSD] make all further usage of the kernel vnode optional.

* [FreeBSD] add the filename, the most important thing lsof does.

* [FreeBSD] many procfs fixes.
Instead of only supporting procfs on FreeBSD < 5, and building pseudofs
otherwise, enable it unconditionally and enable pseudofs as available.
Detect procfs presence at runtime instead of compile time. Stop using
kernel structures for procfs and derive the TYPE from the kinfo_file path.
Remove the /proc/<pid>/ctl entry which doesn't exist.

* [FreeBSD] refactor procfs path parsing code into its own function.

* [FreeBSD] fix a crash when listing a nullfs node whose kernel vnode we can't read.

* [FreeBSD] FreeBSD < 13 didn't always have struct xtcpcb field t_maxseg.

* [FreeBSD] make the socket code compatible with FreeBSD < 12.

* [FreeBSD] make the vnode code compatible with FreeBSD < 12.

* [FreeBSD] retrieve the PCB pointer of the peer UNIX socket from
struct kinfo_file's kf_un.kf_sock.kf_sock_unpconn instead of
struct xunpcb's unp_conn, as the former worked in earlier FreeBSD
versions.

* [FreeBSD] deal with struct xtcpcb on FreeBSD < 1200026.

* [FreeBSD] link to libutil on all FreeBSD versions that had it.

* [FreeBSD] fix some procfs regressions. Call strrchr() on the right string.
If there is a single procfs mount, store it in Mtprocfs.

* [FreeBSD] fix procfs file searches when there are multiple procfs mountpoints.
Fixes issue #185 for FreeBSD.

* [FreeBSD] disable HASNCACHE. We use struct kinfo_file's kf_path instead.

* [FreeBSD] update 00DIST, add a note to 00PORTING, and change to Github
username in 00CREDITS.

* [FreeBSD] use the so_state field from struct kinfo_file.

Also fix the regression in 94f3db7 where the wrong snd state
was being checked.

* [FreeBSD] No more ncache. Get the vnode address from the xfile, if not in xvnode.

* [FreeBSD] for kernel version >= 1400052, use the new struct kinfo_file
instead of KVM access.

* [FreeBSD] fix a build error on FreeBSD 13 due to a duplicate
definition of struct syscall_args.

* [FreeBSD] eliminate the use of struct xvnode, it doesn't work
and isn't feasible (sysctl disabled, would need to fetch 10^6 nodes)
or necessary.

* [FreeBSD] distinguish mountpoints by fsid, not the kernel struct mount pointer.

* [FreeBSD] pre-cache mount info from all files before processing them,
as files without paths may need it from other files on their fs
with paths.

* [FreeBSD] add support for eventfd file descriptors.

* [FreeBSD] print the eventfd address where available.

* [FreeBSD] add support for the SHM file type. Derive file flags from
kinfo_file flags when the struct xfile is not available.

* [FreeBSD] F_RDLCK and F_WRLCK were never lock flags, they're
mutually exclusive lock types.

* [FreeBSD] use the new kern.lockf sysctl to retrieve file lock info
where available, instead of kvm access.

* [FreeBSD] eliminate kvm access for nullfs, modify the path based
on the l_vfs entry for the file instead.

* [FreeBSD] eliminate all kvm access on new enough FreeBSD versions

* [FreeBSD] add support for the PROCDESC file type.

* [FreeBSD] Use the advisory lock lookup API that actually exists in FreeBSD CURRENT,
instead of the experimental one I developed.

* [FreeBSD] Check for the released version of the kernel patch.

* [FreeBSD] FreeBSD 9 under-reports the memory requires for the KERN_FILE sysctl,
so increase it ourselves.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant