Bug 272127 - fdescfs with linkrdlnk fails openat with O_DIRECTORY unless "ls -l" done in fdescfs dir first...
Summary: fdescfs with linkrdlnk fails openat with O_DIRECTORY unless "ls -l" done in f...
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 13.2-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-06-21 08:17 UTC by Peter Eriksson
Modified: 2024-04-08 17:09 UTC (History)
4 users (show)

See Also:


Attachments
Test program (5.53 KB, text/plain)
2023-06-21 14:00 UTC, Peter Eriksson
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Eriksson 2023-06-21 08:17:09 UTC
Seems like the kernel doesn't follow the fdescfs symlink when checking if the target points to a directory for openat (and open) with the O_DIRECTORY flag. 

Unless you've primed it with an "ls -l" in the directory (or something similar that does a stat() call). Then it starts to work. To "reset" - unmount and remount the fdescfs filesystem again

(Thought I was going insane when debugging a problem with Samba 4.18 and Samba failed but my test program worked. Turned out my test program was doing a stat() call before attempting this which primed the cache...)


root@runur00:~ # egrep compat /etc/fstab
none	 	/compat/linux/dev/fd	fdescfs rw,linrdlnk	0	

root@runur00:~ # ./t
./t: openat(AT_FDCWD, "/compat/linux/dev/fd/3", O_DIRECTORY, 0): Not a directory

root@runur00:~ # ls /compat/linux/dev/fd/
0	1	2	3	4

root@runur00:~ # ./t
./t: openat(AT_FDCWD, "/compat/linux/dev/fd/3", O_DIRECTORY, 0): Not a directory
         
root@runur00:~ # ls -l /compat/linux/dev/fd/
total 0
lr-xr-xr-x  1 root  wheel  0 Jun 20 15:57 0 -> /dev/pts/0
lr-xr-xr-x  1 root  wheel  0 Jun 20 15:57 1 -> /dev/pts/0
lr-xr-xr-x  1 root  wheel  0 Jun 20 15:57 2 -> /dev/pts/0
lr-xr-xr-x  1 root  wheel  0 Jun 20 15:57 3 -> /root
lr-xr-xr-x  1 root  wheel  0 Jun 20 15:57 4 -> /etc/spwd.db

root@runur00:~ # ./t
/compat/linux/dev/fd/3: OK

root@runur00:~ # umount /compat/linux/dev/fd
root@runur00:~ # mount /compat/linux/dev/fd

root@runur00:~ # ./t
./t: openat(AT_FDCWD, "/compat/linux/dev/fd/3", O_DIRECTORY, 0): Not a directory



Test program:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>


int
main(int argc,
     char *argv[]) {
  int dfd, tfd;
  char buf[2048];


  dfd = open(".", O_PATH);

  sprintf(buf, "/compat/linux/dev/fd/%d", dfd);
  tfd = openat(AT_FDCWD, buf, O_DIRECTORY, 0);
  if (tfd < 0) {
    fprintf(stderr, "%s: openat(AT_FDCWD, \"%s\", O_DIRECTORY, 0): %s\n", argv[0], buf, strerror(errno));
    exit(1);
  }
  printf("%s: OK\n", buf);

  exit(0);
}
Comment 1 Konstantin Belousov freebsd_committer freebsd_triage 2023-06-21 13:36:18 UTC
PR 255625 / D30131 fixes that.  I believe it was not committed waiting on
your feedback.

But even with D30131 applied, the result of your test program is EACCES, because
you opened fd 3 with O_PATH.  You need nodup option for that to work, but it is
kind of incompatible with linrdlnk for obvious reasons.
Comment 2 Peter Eriksson 2023-06-21 13:58:47 UTC
It's not just related to O_DIRECTORY but a more general problem with fdescfs...

root@runur00:/export/build/samba # umount /compat/linux/dev/fd
root@runur00:/export/build/samba # mount /compat/linux/dev/fd

root@runur00:/export/build/samba # ./t -d /home/peter86 RUNUR00
open("/home/peter86", O_PATH) -> 3
  facl(3, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)]
  openat(3, "RUNUR00", O_RDONLY) -> 4
    facl(4, ACE_GETACLCNT) -> 3
    acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> -1 [errno=78 (Function not implemented)]
  openat(3, "RUNUR00", O_PATH) -> 4
    facl(4, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)]
    acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> -1 [errno=78 (Function not implemented)]
    openat(4, "", O_EMPTY_PATH) -> 5
      facl(5, ACE_GETACLCNT) -> 3
    open("/compat/linux/dev/fd/4", O_RDONLY) -> -1 [errno=20 (Not a directory)]

root@runur00:/export/build/samba # ls -ld /home/peter86/RUNUR00
drwx------+ 2 peter86  employee-liu.se  2 Jun 20 10:52 /home/peter86/RUNUR00

root@runur00:/export/build/samba # ./t -ssd /home/peter86 RUNUR00
open("/home/peter86", O_PATH) -> 3
  facl(3, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)]
  openat(3, "RUNUR00", O_RDONLY) -> 4
    facl(4, ACE_GETACLCNT) -> 3
    stat("/compat/linux/dev/fd/4") -> 0 [type=symlink, size=0, uid=0, gid=0]
    readlink("/compat/linux/dev/fd/4") -> 28 [path=/export/home/peter86/RUNUR00]
    stat("/compat/linux/dev/fd/4") -> 0 [type=dir, size=2, uid=1003258, gid=100001000]
    acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3
  openat(3, "RUNUR00", O_PATH) -> 4
    facl(4, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)]
    stat("/compat/linux/dev/fd/4") -> 0 [type=dir, size=2, uid=1003258, gid=100001000]
    stat("/compat/linux/dev/fd/4") -> 0 [type=dir, size=2, uid=1003258, gid=100001000]
    acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3
    openat(4, "", O_EMPTY_PATH) -> 5
      facl(5, ACE_GETACLCNT) -> 3
    open("/compat/linux/dev/fd/4", O_RDONLY) -> 5
      facl(5, ACE_GETACLCNT) -> 3

root@runur00:/export/build/samba # ./t -d /home/peter86 RUNUR00
open("/home/peter86", O_PATH) -> 3
  facl(3, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)]
  openat(3, "RUNUR00", O_RDONLY) -> 4
    facl(4, ACE_GETACLCNT) -> 3
    acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3
  openat(3, "RUNUR00", O_PATH) -> 4
    facl(4, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)]
    acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3
    openat(4, "", O_EMPTY_PATH) -> 5
      facl(5, ACE_GETACLCNT) -> 3
    open("/compat/linux/dev/fd/4", O_RDONLY) -> 5
      facl(5, ACE_GETACLCNT) -> 3


See how the first stat() call to a fd in the fdescfs also gives invalid size, uid & gid data but as soon as that stat call has pulled in the information about the target things work fine.
Comment 3 Peter Eriksson 2023-06-21 14:00:41 UTC
Created attachment 242920 [details]
Test program
Comment 4 Konstantin Belousov freebsd_committer freebsd_triage 2023-06-21 16:42:51 UTC
Try https://reviews.freebsd.org/D40700
Comment 5 Peter Eriksson 2023-06-21 19:33:59 UTC
(In reply to Konstantin Belousov from comment #4)

A custom kernel with that fix seems to solve the problem!

# umount /compat/linux/dev/fd
# mount /compat/linux/dev/fd
# ./tst -axrd /home/peter86 RUNUR00
open("/home/peter86", O_PATH) -> 3
  facl(3, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)]
  extattr_list_fd(3, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0
  extattr_list_fd(3, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0
  extattr_list_fd(3, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0
  openat(3, "RUNUR00", O_RDONLY) -> 4
    facl(4, ACE_GETACLCNT) -> 3
    facl(4, ACE_GETACL) -> 3
    extattr_list_fd(4, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0
    extattr_list_fd(4, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0
    extattr_list_fd(4, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0
    acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3
    acl("/compat/linux/dev/fd/4", ACE_GETACL) -> 3
    extattr_list_file("/compat/linux/dev/fd/4", EXTATTR_NAMESPACE_USER, NULL, 0) -> 0
    extattr_list_file("/compat/linux/dev/fd/4", EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0
  openat(3, "RUNUR00", O_PATH) -> 4
    facl(4, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)]
    extattr_list_fd(4, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0
    extattr_list_fd(4, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0
    extattr_list_fd(4, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0
    acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3
    acl("/compat/linux/dev/fd/4", ACE_GETACL) -> 3
    extattr_list_file("/compat/linux/dev/fd/4", EXTATTR_NAMESPACE_USER, NULL, 0) -> 0
    extattr_list_file("/compat/linux/dev/fd/4", EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0
    openat(4, "", O_EMPTY_PATH) -> 5
      facl(5, ACE_GETACLCNT) -> 3
      facl(5, ACE_GETACL) -> 3
      extattr_list_fd(5, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0
      extattr_list_fd(5, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0
      extattr_list_fd(5, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0
    open("/compat/linux/dev/fd/4", O_RDONLY|O_DIRECTORY) -> 5
      facl(5, ACE_GETACLCNT) -> 3
      facl(5, ACE_GETACL) -> 3
      extattr_list_fd(5, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0
      extattr_list_fd(5, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0
      extattr_list_fd(5, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0
Comment 6 commit-hook freebsd_committer freebsd_triage 2023-06-27 10:43:56 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=3bffa2262328e4ff1737516f176107f607e7bc76

commit 3bffa2262328e4ff1737516f176107f607e7bc76
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-06-22 13:30:59 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-06-27 10:43:17 +0000

    fdescfs: improve linrdlnk mount option

    Instead of using VV_READLINK vnode flag and checking it in one place,
    just assign VLNK type to the Fdesc vnodes for linrdlnk mounts.  Then all
    places where symlinks needs to be followed, e.g. lookup(), are handled.

    PR:     272127
    Reported by:    Peter Eriksson <pen@lysator.liu.se>
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D40700

 sys/fs/fdescfs/fdesc_vnops.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Comment 7 commit-hook freebsd_committer freebsd_triage 2023-07-04 03:19:30 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=109230f383ac5a60a7bd4e40bbde361c28c430cf

commit 109230f383ac5a60a7bd4e40bbde361c28c430cf
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-06-22 13:30:59 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-07-04 03:06:46 +0000

    fdescfs: improve linrdlnk mount option

    PR:     272127

    (cherry picked from commit 3bffa2262328e4ff1737516f176107f607e7bc76)

 sys/fs/fdescfs/fdesc_vnops.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Comment 8 Dmitry Chagin freebsd_committer freebsd_triage 2023-07-07 19:14:03 UTC
I suspect you are trying to use a linux specific fdescfs linrdlnk mount for a native application?
Comment 9 commit-hook freebsd_committer freebsd_triage 2023-07-13 01:18:35 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=3905309dfeeb89f03b09c347f7ac0a863faa3975

commit 3905309dfeeb89f03b09c347f7ac0a863faa3975
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-07-11 05:03:49 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-07-13 01:14:20 +0000

    fdescfs: add a mount option rdlnk

    which changes /dev/fd/N files types to symbolic link with the behavior
    of symbolic links.

    PR:     272127
    Reported by:    Peter Eriksson <pen@lysator.liu.se>
    Reviewed by:    dchagin
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D40969

 sys/fs/fdescfs/fdesc.h        |  1 +
 sys/fs/fdescfs/fdesc_vfsops.c |  2 ++
 sys/fs/fdescfs/fdesc_vnops.c  | 15 ++++++++++-----
 3 files changed, 13 insertions(+), 5 deletions(-)
Comment 10 commit-hook freebsd_committer freebsd_triage 2023-07-20 12:43:36 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=da56eae4404d4d273cc4a8b7d8f05547bb188599

commit da56eae4404d4d273cc4a8b7d8f05547bb188599
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-07-11 05:03:49 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-07-20 12:20:09 +0000

    fdescfs: add a mount option rdlnk

    PR:     272127

    (cherry picked from commit 3905309dfeeb89f03b09c347f7ac0a863faa3975)

 sys/fs/fdescfs/fdesc.h        |  1 +
 sys/fs/fdescfs/fdesc_vfsops.c |  2 ++
 sys/fs/fdescfs/fdesc_vnops.c  | 16 ++++++++++------
 3 files changed, 13 insertions(+), 6 deletions(-)