All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vivek Goyal <vgoyal@redhat.com>
To: Max Reitz <mreitz@redhat.com>
Cc: virtio-fs@redhat.com, qemu-devel@nongnu.org
Subject: Re: [Virtio-fs] [PATCH v3 06/10] virtiofsd: Let lo_inode_open() return a TempFd
Date: Fri, 6 Aug 2021 15:55:01 -0400	[thread overview]
Message-ID: <YQ2TleuDejJY4O4V@redhat.com> (raw)
In-Reply-To: <20210730150134.216126-7-mreitz@redhat.com>

On Fri, Jul 30, 2021 at 05:01:30PM +0200, Max Reitz wrote:
> Strictly speaking, this is not necessary, because lo_inode_open() will
> always return a new FD owned by the caller, so TempFd.owned will always
> be true.
> 
> However, auto-cleanup is nice, and in some cases this plays nicely with
> an lo_inode_fd() call in another conditional branch (see lo_setattr()).
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  tools/virtiofsd/passthrough_ll.c | 138 +++++++++++++------------------
>  1 file changed, 59 insertions(+), 79 deletions(-)
> 
> diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
> index 9e1bc37af8..292b7f7e27 100644
> --- a/tools/virtiofsd/passthrough_ll.c
> +++ b/tools/virtiofsd/passthrough_ll.c
> @@ -291,10 +291,8 @@ static void temp_fd_clear(TempFd *temp_fd)
>  /**
>   * Return an owned fd from *temp_fd that will not be closed when
>   * *temp_fd goes out of scope.
> - *
> - * (TODO: Remove __attribute__ once this is used.)
>   */
> -static __attribute__((unused)) int temp_fd_steal(TempFd *temp_fd)
> +static int temp_fd_steal(TempFd *temp_fd)
>  {
>      if (temp_fd->owned) {
>          temp_fd->owned = false;
> @@ -673,9 +671,12 @@ static int lo_fd(fuse_req_t req, fuse_ino_t ino, TempFd *tfd)
>   * when a malicious client opens special files such as block device nodes.
>   * Symlink inodes are also rejected since symlinks must already have been
>   * traversed on the client side.
> + *
> + * The fd is returned in tfd->fd.  The return value is 0 on success and -errno
> + * otherwise.
>   */
> -static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode,
> -                         int open_flags)
> +static int lo_inode_open(const struct lo_data *lo, const struct lo_inode *inode,
> +                         int open_flags, TempFd *tfd)
>  {
>      g_autofree char *fd_str = g_strdup_printf("%d", inode->fd);
>      int fd;
> @@ -694,7 +695,13 @@ static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode,
>      if (fd < 0) {
>          return -errno;
>      }
> -    return fd;
> +
> +    *tfd = (TempFd) {
> +        .fd = fd,
> +        .owned = true,
> +    };
> +
> +    return 0;
>  }
>  
>  static void lo_init(void *userdata, struct fuse_conn_info *conn)
> @@ -852,7 +859,12 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
>          return;
>      }
>  
> -    res = lo_inode_fd(inode, &inode_fd);
> +    if (!fi && (valid & FUSE_SET_ATTR_SIZE)) {
> +        /* We need an O_RDWR FD for ftruncate() */
> +        res = lo_inode_open(lo, inode, O_RDWR, &inode_fd);
> +    } else {
> +        res = lo_inode_fd(inode, &inode_fd);
> +    }

A minor nit.

So inode_fd could hold either an O_PATH fd returned by lo_inode_fd()
or a O_RDWR fd returned by lo_inode_open().

Previous code held these fds in two different variables, inode_fd and
truncfd respectively. I kind of found that easier to read because looking
at variable name, I knew whether I am dealing with O_PATH fd or an
O_RDWR fd I just opened. 

So a minor nit. We could continue to have two variables, say
inode_fd and trunc_fd. Just that type of trunc_fd will now be TempFd.

Also I liked previous style easier to read where I always got hold
of O_PATH fd first. And later opened a O_RDWR fd if operation
is FUSE_ATTR_SIZE. So "valid & FUSE_SET_ATTR_SIZE" check was not
at two places.

Anyway, this is a minor nit. If you don't like the idea of using
two separate variables to hold O_PATH fd and O_RDWR fd, that's ok.


>      if (res < 0) {
>          saverr = -res;
>          goto out_err;
> @@ -900,18 +912,11 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
>          if (fi) {
>              truncfd = fd;
>          } else {
> -            truncfd = lo_inode_open(lo, inode, O_RDWR);
> -            if (truncfd < 0) {
> -                saverr = -truncfd;
> -                goto out_err;
> -            }
> +            truncfd = inode_fd.fd;
>          }
>  
>          saverr = drop_security_capability(lo, truncfd);
>          if (saverr) {
> -            if (!fi) {
> -                close(truncfd);
> -            }
>              goto out_err;
>          }
>  
> @@ -919,9 +924,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
>              res = drop_effective_cap("FSETID", &cap_fsetid_dropped);
>              if (res != 0) {
>                  saverr = res;
> -                if (!fi) {
> -                    close(truncfd);
> -                }
>                  goto out_err;
>              }
>          }
> @@ -934,9 +936,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
>                  fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n");
>              }
>          }
> -        if (!fi) {
> -            close(truncfd);
> -        }
>          if (res == -1) {
>              goto out_err;
>          }
> @@ -1822,11 +1821,12 @@ static struct lo_dirp *lo_dirp(fuse_req_t req, struct fuse_file_info *fi)
>  static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
>                         struct fuse_file_info *fi)
>  {
> +    g_auto(TempFd) inode_fd = TEMP_FD_INIT;
>      int error = ENOMEM;
>      struct lo_data *lo = lo_data(req);
>      struct lo_inode *inode;
>      struct lo_dirp *d = NULL;
> -    int fd;
> +    int res;
>      ssize_t fh;
>  
>      inode = lo_inode(req, ino);
> @@ -1840,13 +1840,13 @@ static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
>          goto out_err;
>      }
>  
> -    fd = lo_inode_open(lo, inode, O_RDONLY);
> -    if (fd < 0) {
> -        error = -fd;
> +    res = lo_inode_open(lo, inode, O_RDONLY, &inode_fd);
> +    if (res < 0) {
> +        error = -res;
>          goto out_err;
>      }
>  
> -    d->dp = fdopendir(fd);
> +    d->dp = fdopendir(temp_fd_steal(&inode_fd));

So we are using temp_fd_steal(), because if fdopendir() is succesful,
we don't want to close fd instead it will be closed during closedir()
call. inode_fd will be closed once lo_opendir(), so we get fd ownership
which will need to close explicitly, when appropriate.

Who closes the stolen fd returned by temp_fd_steal() if fdopendir() fails?

>      if (d->dp == NULL) {
>          goto out_errno;
>      }
> @@ -1876,8 +1876,6 @@ out_err:
>      if (d) {
>          if (d->dp) {
>              closedir(d->dp);
> -        } else if (fd != -1) {
> -            close(fd);
>          }
>          free(d);
>      }
> @@ -2077,6 +2075,7 @@ static void update_open_flags(int writeback, int allow_direct_io,
>  static int lo_do_open(struct lo_data *lo, struct lo_inode *inode,
>                        int existing_fd, struct fuse_file_info *fi)
>  {
> +    g_auto(TempFd) inode_fd = TEMP_FD_INIT;

It bothers me that we are using variable inode_fd both to hold O_PATH
fd as well as regular fd. Will be nice if just by looking at variable
name I could figure out which type of fd it is.

Will it make sense to use path_fd, or ipath_fd, or inode_path_fd to
represent where we are using O_PATH fd.


Thanks
Vivek


WARNING: multiple messages have this Message-ID (diff)
From: Vivek Goyal <vgoyal@redhat.com>
To: Max Reitz <mreitz@redhat.com>
Cc: virtio-fs@redhat.com, qemu-devel@nongnu.org,
	Stefan Hajnoczi <stefanha@redhat.com>,
	"Dr . David Alan Gilbert" <dgilbert@redhat.com>
Subject: Re: [PATCH v3 06/10] virtiofsd: Let lo_inode_open() return a TempFd
Date: Fri, 6 Aug 2021 15:55:01 -0400	[thread overview]
Message-ID: <YQ2TleuDejJY4O4V@redhat.com> (raw)
In-Reply-To: <20210730150134.216126-7-mreitz@redhat.com>

On Fri, Jul 30, 2021 at 05:01:30PM +0200, Max Reitz wrote:
> Strictly speaking, this is not necessary, because lo_inode_open() will
> always return a new FD owned by the caller, so TempFd.owned will always
> be true.
> 
> However, auto-cleanup is nice, and in some cases this plays nicely with
> an lo_inode_fd() call in another conditional branch (see lo_setattr()).
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  tools/virtiofsd/passthrough_ll.c | 138 +++++++++++++------------------
>  1 file changed, 59 insertions(+), 79 deletions(-)
> 
> diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
> index 9e1bc37af8..292b7f7e27 100644
> --- a/tools/virtiofsd/passthrough_ll.c
> +++ b/tools/virtiofsd/passthrough_ll.c
> @@ -291,10 +291,8 @@ static void temp_fd_clear(TempFd *temp_fd)
>  /**
>   * Return an owned fd from *temp_fd that will not be closed when
>   * *temp_fd goes out of scope.
> - *
> - * (TODO: Remove __attribute__ once this is used.)
>   */
> -static __attribute__((unused)) int temp_fd_steal(TempFd *temp_fd)
> +static int temp_fd_steal(TempFd *temp_fd)
>  {
>      if (temp_fd->owned) {
>          temp_fd->owned = false;
> @@ -673,9 +671,12 @@ static int lo_fd(fuse_req_t req, fuse_ino_t ino, TempFd *tfd)
>   * when a malicious client opens special files such as block device nodes.
>   * Symlink inodes are also rejected since symlinks must already have been
>   * traversed on the client side.
> + *
> + * The fd is returned in tfd->fd.  The return value is 0 on success and -errno
> + * otherwise.
>   */
> -static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode,
> -                         int open_flags)
> +static int lo_inode_open(const struct lo_data *lo, const struct lo_inode *inode,
> +                         int open_flags, TempFd *tfd)
>  {
>      g_autofree char *fd_str = g_strdup_printf("%d", inode->fd);
>      int fd;
> @@ -694,7 +695,13 @@ static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode,
>      if (fd < 0) {
>          return -errno;
>      }
> -    return fd;
> +
> +    *tfd = (TempFd) {
> +        .fd = fd,
> +        .owned = true,
> +    };
> +
> +    return 0;
>  }
>  
>  static void lo_init(void *userdata, struct fuse_conn_info *conn)
> @@ -852,7 +859,12 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
>          return;
>      }
>  
> -    res = lo_inode_fd(inode, &inode_fd);
> +    if (!fi && (valid & FUSE_SET_ATTR_SIZE)) {
> +        /* We need an O_RDWR FD for ftruncate() */
> +        res = lo_inode_open(lo, inode, O_RDWR, &inode_fd);
> +    } else {
> +        res = lo_inode_fd(inode, &inode_fd);
> +    }

A minor nit.

So inode_fd could hold either an O_PATH fd returned by lo_inode_fd()
or a O_RDWR fd returned by lo_inode_open().

Previous code held these fds in two different variables, inode_fd and
truncfd respectively. I kind of found that easier to read because looking
at variable name, I knew whether I am dealing with O_PATH fd or an
O_RDWR fd I just opened. 

So a minor nit. We could continue to have two variables, say
inode_fd and trunc_fd. Just that type of trunc_fd will now be TempFd.

Also I liked previous style easier to read where I always got hold
of O_PATH fd first. And later opened a O_RDWR fd if operation
is FUSE_ATTR_SIZE. So "valid & FUSE_SET_ATTR_SIZE" check was not
at two places.

Anyway, this is a minor nit. If you don't like the idea of using
two separate variables to hold O_PATH fd and O_RDWR fd, that's ok.


>      if (res < 0) {
>          saverr = -res;
>          goto out_err;
> @@ -900,18 +912,11 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
>          if (fi) {
>              truncfd = fd;
>          } else {
> -            truncfd = lo_inode_open(lo, inode, O_RDWR);
> -            if (truncfd < 0) {
> -                saverr = -truncfd;
> -                goto out_err;
> -            }
> +            truncfd = inode_fd.fd;
>          }
>  
>          saverr = drop_security_capability(lo, truncfd);
>          if (saverr) {
> -            if (!fi) {
> -                close(truncfd);
> -            }
>              goto out_err;
>          }
>  
> @@ -919,9 +924,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
>              res = drop_effective_cap("FSETID", &cap_fsetid_dropped);
>              if (res != 0) {
>                  saverr = res;
> -                if (!fi) {
> -                    close(truncfd);
> -                }
>                  goto out_err;
>              }
>          }
> @@ -934,9 +936,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
>                  fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n");
>              }
>          }
> -        if (!fi) {
> -            close(truncfd);
> -        }
>          if (res == -1) {
>              goto out_err;
>          }
> @@ -1822,11 +1821,12 @@ static struct lo_dirp *lo_dirp(fuse_req_t req, struct fuse_file_info *fi)
>  static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
>                         struct fuse_file_info *fi)
>  {
> +    g_auto(TempFd) inode_fd = TEMP_FD_INIT;
>      int error = ENOMEM;
>      struct lo_data *lo = lo_data(req);
>      struct lo_inode *inode;
>      struct lo_dirp *d = NULL;
> -    int fd;
> +    int res;
>      ssize_t fh;
>  
>      inode = lo_inode(req, ino);
> @@ -1840,13 +1840,13 @@ static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
>          goto out_err;
>      }
>  
> -    fd = lo_inode_open(lo, inode, O_RDONLY);
> -    if (fd < 0) {
> -        error = -fd;
> +    res = lo_inode_open(lo, inode, O_RDONLY, &inode_fd);
> +    if (res < 0) {
> +        error = -res;
>          goto out_err;
>      }
>  
> -    d->dp = fdopendir(fd);
> +    d->dp = fdopendir(temp_fd_steal(&inode_fd));

So we are using temp_fd_steal(), because if fdopendir() is succesful,
we don't want to close fd instead it will be closed during closedir()
call. inode_fd will be closed once lo_opendir(), so we get fd ownership
which will need to close explicitly, when appropriate.

Who closes the stolen fd returned by temp_fd_steal() if fdopendir() fails?

>      if (d->dp == NULL) {
>          goto out_errno;
>      }
> @@ -1876,8 +1876,6 @@ out_err:
>      if (d) {
>          if (d->dp) {
>              closedir(d->dp);
> -        } else if (fd != -1) {
> -            close(fd);
>          }
>          free(d);
>      }
> @@ -2077,6 +2075,7 @@ static void update_open_flags(int writeback, int allow_direct_io,
>  static int lo_do_open(struct lo_data *lo, struct lo_inode *inode,
>                        int existing_fd, struct fuse_file_info *fi)
>  {
> +    g_auto(TempFd) inode_fd = TEMP_FD_INIT;

It bothers me that we are using variable inode_fd both to hold O_PATH
fd as well as regular fd. Will be nice if just by looking at variable
name I could figure out which type of fd it is.

Will it make sense to use path_fd, or ipath_fd, or inode_path_fd to
represent where we are using O_PATH fd.


Thanks
Vivek



  reply	other threads:[~2021-08-06 19:55 UTC|newest]

Thread overview: 88+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-30 15:01 [Virtio-fs] [PATCH v3 00/10] virtiofsd: Allow using file handles instead of O_PATH FDs Max Reitz
2021-07-30 15:01 ` Max Reitz
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 01/10] virtiofsd: Limit setxattr()'s creds-dropped region Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-06 14:16   ` [Virtio-fs] " Vivek Goyal
2021-08-06 14:16     ` Vivek Goyal
2021-08-09 10:30     ` [Virtio-fs] " Max Reitz
2021-08-09 10:30       ` Max Reitz
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 02/10] virtiofsd: Add TempFd structure Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-06 14:41   ` [Virtio-fs] " Vivek Goyal
2021-08-06 14:41     ` Vivek Goyal
2021-08-09 10:44     ` [Virtio-fs] " Max Reitz
2021-08-09 10:44       ` Max Reitz
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 03/10] virtiofsd: Use lo_inode_open() instead of openat() Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-06 15:42   ` [Virtio-fs] " Vivek Goyal
2021-08-06 15:42     ` Vivek Goyal
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 04/10] virtiofsd: Add lo_inode_fd() helper Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-06 18:25   ` [Virtio-fs] " Vivek Goyal
2021-08-06 18:25     ` Vivek Goyal
2021-08-09 10:48     ` [Virtio-fs] " Max Reitz
2021-08-09 10:48       ` Max Reitz
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 05/10] virtiofsd: Let lo_fd() return a TempFd Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 06/10] virtiofsd: Let lo_inode_open() " Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-06 19:55   ` Vivek Goyal [this message]
2021-08-06 19:55     ` Vivek Goyal
2021-08-09 13:40     ` [Virtio-fs] " Max Reitz
2021-08-09 13:40       ` Max Reitz
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 07/10] virtiofsd: Add lo_inode.fhandle Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-09 15:21   ` [Virtio-fs] " Vivek Goyal
2021-08-09 15:21     ` Vivek Goyal
2021-08-09 16:41     ` [Virtio-fs] " Hanna Reitz
2021-08-09 16:41       ` Hanna Reitz
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 08/10] virtiofsd: Add inodes_by_handle hash table Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-09 16:10   ` [Virtio-fs] " Vivek Goyal
2021-08-09 16:10     ` Vivek Goyal
2021-08-09 16:47     ` [Virtio-fs] " Hanna Reitz
2021-08-09 16:47       ` Hanna Reitz
2021-08-10 14:07       ` [Virtio-fs] " Vivek Goyal
2021-08-10 14:07         ` Vivek Goyal
2021-08-10 14:13         ` [Virtio-fs] " Hanna Reitz
2021-08-10 14:13           ` Hanna Reitz
2021-08-10 17:51           ` [Virtio-fs] " Vivek Goyal
2021-08-10 17:51             ` Vivek Goyal
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 09/10] virtiofsd: Optionally fill lo_inode.fhandle Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-09 18:41   ` [Virtio-fs] " Vivek Goyal
2021-08-09 18:41     ` Vivek Goyal
2021-08-10  8:32     ` [Virtio-fs] " Hanna Reitz
2021-08-10  8:32       ` Hanna Reitz
2021-08-10 15:23       ` [Virtio-fs] " Vivek Goyal
2021-08-10 15:23         ` Vivek Goyal
2021-08-10 15:26         ` [Virtio-fs] " Hanna Reitz
2021-08-10 15:26           ` Hanna Reitz
2021-08-10 15:57           ` [Virtio-fs] " Vivek Goyal
2021-08-10 15:57             ` Vivek Goyal
2021-08-11  6:41             ` [Virtio-fs] " Hanna Reitz
2021-08-11  6:41               ` Hanna Reitz
2021-08-16 19:44               ` [Virtio-fs] " Vivek Goyal
2021-08-16 19:44                 ` Vivek Goyal
2021-08-17  8:27                 ` [Virtio-fs] " Hanna Reitz
2021-08-17  8:27                   ` Hanna Reitz
2021-08-17 19:45                   ` [Virtio-fs] " Vivek Goyal
2021-08-17 19:45                     ` Vivek Goyal
2021-08-18  0:14                     ` [Virtio-fs] " Vivek Goyal
2021-08-18  0:14                       ` Vivek Goyal
2021-08-18 13:32                       ` [Virtio-fs] " Vivek Goyal
2021-08-18 13:32                         ` Vivek Goyal
2021-08-18 13:48                         ` [Virtio-fs] " Hanna Reitz
2021-08-18 13:48                           ` Hanna Reitz
2021-08-19 16:38   ` [Virtio-fs] " Dr. David Alan Gilbert
2021-08-19 16:38     ` Dr. David Alan Gilbert
2021-07-30 15:01 ` [Virtio-fs] [PATCH v3 10/10] virtiofsd: Add lazy lo_do_find() Max Reitz
2021-07-30 15:01   ` Max Reitz
2021-08-09 19:08   ` [Virtio-fs] " Vivek Goyal
2021-08-09 19:08     ` Vivek Goyal
2021-08-10  8:38     ` [Virtio-fs] " Hanna Reitz
2021-08-10  8:38       ` Hanna Reitz
2021-08-10 14:12       ` [Virtio-fs] " Vivek Goyal
2021-08-10 14:12         ` Vivek Goyal
2021-08-10 14:17         ` [Virtio-fs] " Hanna Reitz
2021-08-10 14:17           ` Hanna Reitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YQ2TleuDejJY4O4V@redhat.com \
    --to=vgoyal@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=virtio-fs@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.