Created attachment 246324 [details] helloworld-dir.c While it is not common to read(2) a directory directly, this is still supported in FreeBSD (with security.bsd.allow_read_dir=1); and it could be actually useful in FUSE as an user space file system implementation may provide some data in a directory itself. The followings demonstrate the issue with a FUSE-based file system: # sysctl security.bsd.allow_read_dir=1 security.bsd.allow_read_dir: 0 -> 1 # helloworld-dir /mnt/3/ # ls -al /mnt/3/ total 0 drwxr-xr-x 2 root wheel 27 Jan 1 1970 . drwxr-xr-x 2 root wheel 13 Jan 1 1970 hello # ls -al /mnt/3/hello/ total 0 drwxr-xr-x 2 root wheel 13 Jan 1 1970 . drwxr-xr-x 2 root wheel 27 Jan 1 1970 .. -rw-r--r-- 1 root wheel 12 Jan 1 1970 world # cat /mnt/3/hello/world Hello world # cat /mnt/3/hello cat: stdout: Is a directory # dd status=none if=/mnt/3/hello Hello world! # cat /mnt/3/ cat: stdout: Is a directory # dd status=none if=/mnt/3/ This is the root directory # umount /mnt/3/ It shows that cat(1) failed to read the directories but dd(1) works without problem. The cause is that cat(1) tries to use copy_file_range(2) to copy input file to stdout but this system call dosen't work on directories as documented, and cat(1) didn't fallback to read(2) and write(2) on copy_file_range(2) fail with EISDIR. The FUSE program for demonstration is attached.
Created attachment 246325 [details] Proposed fix cat(1) should fallback to the read(2) system call if copy_file_range(2) failed with EISDIR.
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=3c773cad57064c23873f286fbec69f6f0305b889 commit 3c773cad57064c23873f286fbec69f6f0305b889 Author: Martin Matuska <mm@FreeBSD.org> AuthorDate: 2023-11-19 01:09:34 +0000 Commit: Martin Matuska <mm@FreeBSD.org> CommitDate: 2023-11-19 01:14:50 +0000 cat: fallback on EISDIR with copy_file_range(2) The filesystem may support reading directories directly when security.bsd.allow_read_dir is set. MFC after: 1 week PR: 275099 bin/cat/cat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
A commit in branch stable/14 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=a4d16707a81b13cb711a4a75843d5d24486de150 commit a4d16707a81b13cb711a4a75843d5d24486de150 Author: Martin Matuska <mm@FreeBSD.org> AuthorDate: 2023-11-19 01:09:34 +0000 Commit: Martin Matuska <mm@FreeBSD.org> CommitDate: 2023-11-26 00:24:42 +0000 cat: fallback on EISDIR with copy_file_range(2) The filesystem may support reading directories directly when security.bsd.allow_read_dir is set. PR: 275099 (cherry picked from commit 3c773cad57064c23873f286fbec69f6f0305b889) bin/cat/cat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)