Re: [RFC PATCH 2/2] fs: open_by_handle_at() support for decoding connectable file handles

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, Sep 21, 2024 at 7:33 AM Jeff Layton <jlayton@xxxxxxxxxx> wrote:
>
> On Fri, 2024-09-20 at 18:38 +0200, Amir Goldstein wrote:
> > On Fri, Sep 20, 2024 at 6:02 PM Jeff Layton <jlayton@xxxxxxxxxx> wrote:
> > >
> > > On Thu, 2024-09-19 at 16:06 +0200, Amir Goldstein wrote:
> > > > Allow using an O_PATH fd as mount fd argument of open_by_handle_at(2).
> > > > This was not allowed before, so we use it to enable a new API for
> > > > decoding "connectable" file handles that were created using the
> > > > AT_HANDLE_CONNECTABLE flag to name_to_handle_at(2).
> > > >
> > > > When mount fd is an O_PATH fd and decoding an O_PATH fd is requested,
> > > > use that as a hint to try to decode a "connected" fd with known path,
> > > > which is accessible (to capable user) from mount fd path.
> > > >
> > > > Note that this does not check if the path is accessible to the calling
> > > > user, just that it is accessible wrt the mount namesapce, so if there
> > > > is no "connected" alias, or if parts of the path are hidden in the
> > > > mount namespace, open_by_handle_at(2) will return -ESTALE.
> > > >
> > > > Note that the file handles used to decode a "connected" fd do not have
> > > > to be encoded with the AT_HANDLE_CONNECTABLE flag.  Specifically,
> > > > directory file handles are always "connectable", regardless of using
> > > > the AT_HANDLE_CONNECTABLE flag.
> > > >
> > > > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
> > > > ---
> > > >  fs/fhandle.c | 61 +++++++++++++++++++++++++++++++---------------------
> > > >  1 file changed, 37 insertions(+), 24 deletions(-)
> > > >
> > >
> > > The mountfd is only used to get a path, so I don't see a problem with
> > > allowing that to be an O_PATH fd.
> > >
> > > I'm less keen on using the fact that mountfd is an O_PATH fd to change
> > > the behaviour of open_by_handle_at(). That seems very subtle. Is there
> > > a good reason to do it that way instead of just declaring a new AT_*
> > > flag for this?
> > >
> >
> > Not sure if it is a good reason, but open_by_handle_at() has an O_ flags
> > argument, not an AT_ flags argument...
> >
> > If my hack API is not acceptable then we will need to add
> > open_by_handle_at2(), with struct open_how argument or something.
> >
>
> Oh right, I forgot that open_by_handle_at doesn't take AT_* flags.
> A new syscall may be best then.
>
> I can see a couple of other potential approaches:
>
> 1/ You could add a new fcntl() cmd that puts the mountfd into a
> "connectable filehandles" mode. The downside there is that it'd take 2
> syscalls to do your open.
>
> 2/ You could add flags to open_how that make openat2() behave like
> open_by_handle_at(). Add a flag that allows "pathname" to point to a
> filehandle instead, and a second flag that indicates that the fh is
> connectable.
>
> Both of those are pretty hacky though.
>

Yes, especially #2, very creative ;)

But I had another less hacky idea.
Instead of (ab)using a sycall flag to get a "connected" fd,
encode an explicit "connectable" fh, something like this untested patch.

WDYT?

Thanks,
Amir.

--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -59,6 +59,7 @@ static long do_sys_name_to_handle(const struct path *path,
        handle_bytes = handle_dwords * sizeof(u32);
        handle->handle_bytes = handle_bytes;
        if ((handle->handle_bytes > f_handle.handle_bytes) ||
+           WARN_ON_ONCE(retval > FILEID_INVALID) ||
            (retval == FILEID_INVALID) || (retval < 0)) {
                /* As per old exportfs_encode_fh documentation
                 * we could return ENOSPC to indicate overflow
@@ -72,8 +73,21 @@ static long do_sys_name_to_handle(const struct path *path,
                 * non variable part of the file_handle
                 */
                handle_bytes = 0;
-       } else
+       } else {
+               /*
+                * When asked to encode a connectable file handle, encode this
+                * property in the file handle itself, so we know how
to decode it.
+                * For sanity, also encode in the file handle if the
encoded object
+                * is a directory, because connectable directory file
handles do not
+                * encode the parent.
+                */
+               if (fh_flags & EXPORT_FH_CONNECTABLE) {
+                       if (d_is_dir(path->dentry))
+                               fh_flags |= EXPORT_FH_DIR_ONLY;
+                       handle->handle_flags = fh_flags;
+               }
                retval = 0;
+       }
...
@@ -336,6 +350,19 @@ static int handle_to_path(int mountdirfd, struct
file_handle __user *ufh,
                retval = -EINVAL;
                goto out_path;
        }
+       if (f_handle.handle_flags & ~EXPORT_FH_USER_FLAGS) {
+               retval = -EINVAL;
+               goto out_path;
+       }
+       /*
+        * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we
+        * are decoding an fd with connected path, which is accessible from
+        * the mount fd path.
+        */
+       ctx.fh_flags |= f_handle.handle_flags;
+       if (ctx.fh_flags & EXPORT_FH_CONNECTABLE)
+               ctx.flags |= HANDLE_CHECK_SUBTREE;
+
        handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
                         GFP_KERNEL);
...
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -159,6 +159,8 @@ struct fid {
 #define EXPORT_FH_CONNECTABLE  0x1 /* Encode file handle with parent */
 #define EXPORT_FH_FID          0x2 /* File handle may be non-decodeable */
 #define EXPORT_FH_DIR_ONLY     0x4 /* Only decode file handle for a
directory */
+/* Flags allowed in encoded handle_flags that is exported to user */
+#define EXPORT_FH_USER_FLAGS   (EXPORT_FH_CONNECTABLE | EXPORT_FH_DIR_ONLY)
...
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1071,7 +1071,8 @@ struct file {

 struct file_handle {
        __u32 handle_bytes;
-       int handle_type;
+       int handle_type:16;
+       int handle_flags:16;
        /* file identifier */
        unsigned char f_handle[] __counted_by(handle_bytes);
 };





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux