Bug 275099 - cat(1) can't read directories
Summary: cat(1) can't read directories
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Only Me
Assignee: Martin Matuska
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-11-15 06:19 UTC by WHR
Modified: 2023-11-26 00:27 UTC (History)
2 users (show)

See Also:


Attachments
helloworld-dir.c (1.94 KB, text/x-csrc)
2023-11-15 06:19 UTC, WHR
no flags Details
Proposed fix (442 bytes, patch)
2023-11-15 06:25 UTC, WHR
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description WHR 2023-11-15 06:19:57 UTC
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.
Comment 1 WHR 2023-11-15 06:25:28 UTC
Created attachment 246325 [details]
Proposed fix

cat(1) should fallback to the read(2) system call if copy_file_range(2) failed with EISDIR.
Comment 2 commit-hook freebsd_committer freebsd_triage 2023-11-19 01:16:06 UTC
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(-)
Comment 3 commit-hook freebsd_committer freebsd_triage 2023-11-26 00:26:30 UTC
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(-)