Re: [PATCH v4 07/12] virtiofsd: Let lo_inode_open() return a TempFd

2021-10-20 Thread Hanna Reitz

On 18.10.21 21:18, Vivek Goyal wrote:

On Thu, Sep 16, 2021 at 10:40:40AM +0200, Hanna 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.

The auto-cleanup is nice, though.  Also, we get a more unified interface
where you always get a TempFd when you need an FD for an lo_inode
(regardless of whether it is an O_PATH FD or a non-O_PATH FD).

Signed-off-by: Hanna Reitz 
---
  tools/virtiofsd/passthrough_ll.c | 156 +++
  1 file changed, 75 insertions(+), 81 deletions(-)

diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index 3bf20b8659..d257eda129 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -293,10 +293,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;
@@ -309,10 +307,8 @@ static __attribute__((unused)) int temp_fd_steal(TempFd 
*temp_fd)
  /**
   * Create a borrowing copy of an existing TempFd.  Note that *to is
   * only valid as long as *from is valid.
- *
- * (TODO: Remove __attribute__ once this is used.)
   */
-static __attribute__((unused)) void temp_fd_copy(const TempFd *from, TempFd 
*to)
+static void temp_fd_copy(const TempFd *from, TempFd *to)
  {
  *to = (TempFd) {
  .fd = from->fd,
@@ -689,9 +685,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)
+ int open_flags, TempFd *tfd)
  {
  g_autofree char *fd_str = g_strdup_printf("%d", inode->fd);
  int fd;
@@ -710,7 +709,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)

@@ -854,7 +859,8 @@ static int lo_fi_fd(fuse_req_t req, struct fuse_file_info 
*fi)
  static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
 int valid, struct fuse_file_info *fi)
  {
-g_auto(TempFd) path_fd = TEMP_FD_INIT;
+g_auto(TempFd) path_fd = TEMP_FD_INIT; /* at least an O_PATH fd */

What does atleast O_PATH fd mean?


It means it might as well be an O_RDWR FD.  When we open an O_RDWR FD, 
it’s pointless to open an O_PATH FD, too, because we can use the O_RDWR 
FD everywhere where we’d need an O_PATH FD.  Hence in this case, we open 
rw_fd and copy it to path_fd.


Users still use rw_fd and path_fd according to what they need.




+g_auto(TempFd) rw_fd = TEMP_FD_INIT; /* O_RDWR fd */
  int saverr;
  char procname[64];
  struct lo_data *lo = lo_data(req);
@@ -868,7 +874,15 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, 
struct stat *attr,
  return;
  }
  
-res = lo_inode_fd(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, _fd);
+if (res >= 0) {
+temp_fd_copy(_fd, _fd);

I am lost here. If lo_inode_open() failed, why are we calling this
temp_fd_copy()? path_fd is not even a valid fd yet.


We’re calling it on success.


Still beats me that why open rw_fd now instead of down in
FUSE_SET_ATTR_SIZE block. I think we had this discussion and you
had some reasons to move it up.


Because it’s pointless overhead to open two FDs.

Before file handles, getting the O_PATH FD was a trivial operation. If 
we needed an O_RDWR FD later, we’d open it later.  No duplicate work 
involved.


With file handles, getting the O_PATH FD may mean opening a new FD. 
Opening another FD from the same file handle, just with different flags, 
later on would be strange, because we could have just opened the FD as 
O_RDWR right from the start.


Hanna




Re: [PATCH v4 07/12] virtiofsd: Let lo_inode_open() return a TempFd

2021-10-18 Thread Vivek Goyal
On Thu, Sep 16, 2021 at 10:40:40AM +0200, Hanna 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.
> 
> The auto-cleanup is nice, though.  Also, we get a more unified interface
> where you always get a TempFd when you need an FD for an lo_inode
> (regardless of whether it is an O_PATH FD or a non-O_PATH FD).
> 
> Signed-off-by: Hanna Reitz 
> ---
>  tools/virtiofsd/passthrough_ll.c | 156 +++
>  1 file changed, 75 insertions(+), 81 deletions(-)
> 
> diff --git a/tools/virtiofsd/passthrough_ll.c 
> b/tools/virtiofsd/passthrough_ll.c
> index 3bf20b8659..d257eda129 100644
> --- a/tools/virtiofsd/passthrough_ll.c
> +++ b/tools/virtiofsd/passthrough_ll.c
> @@ -293,10 +293,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;
> @@ -309,10 +307,8 @@ static __attribute__((unused)) int temp_fd_steal(TempFd 
> *temp_fd)
>  /**
>   * Create a borrowing copy of an existing TempFd.  Note that *to is
>   * only valid as long as *from is valid.
> - *
> - * (TODO: Remove __attribute__ once this is used.)
>   */
> -static __attribute__((unused)) void temp_fd_copy(const TempFd *from, TempFd 
> *to)
> +static void temp_fd_copy(const TempFd *from, TempFd *to)
>  {
>  *to = (TempFd) {
>  .fd = from->fd,
> @@ -689,9 +685,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)
> + int open_flags, TempFd *tfd)
>  {
>  g_autofree char *fd_str = g_strdup_printf("%d", inode->fd);
>  int fd;
> @@ -710,7 +709,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)
> @@ -854,7 +859,8 @@ static int lo_fi_fd(fuse_req_t req, struct fuse_file_info 
> *fi)
>  static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
> int valid, struct fuse_file_info *fi)
>  {
> -g_auto(TempFd) path_fd = TEMP_FD_INIT;
> +g_auto(TempFd) path_fd = TEMP_FD_INIT; /* at least an O_PATH fd */

What does atleast O_PATH fd mean?

> +g_auto(TempFd) rw_fd = TEMP_FD_INIT; /* O_RDWR fd */
>  int saverr;
>  char procname[64];
>  struct lo_data *lo = lo_data(req);
> @@ -868,7 +874,15 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, 
> struct stat *attr,
>  return;
>  }
>  
> -res = lo_inode_fd(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, _fd);
> +if (res >= 0) {
> +temp_fd_copy(_fd, _fd);

I am lost here. If lo_inode_open() failed, why are we calling this
temp_fd_copy()? path_fd is not even a valid fd yet.

Still beats me that why open rw_fd now instead of down in
FUSE_SET_ATTR_SIZE block. I think we had this discussion and you
had some reasons to move it up.

Vivek

> +}
> +} else {
> +res = lo_inode_fd(inode, _fd);
> +}
>  if (res < 0) {
>  saverr = -res;
>  goto out_err;
> @@ -916,18 +930,12 @@ 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;
> -}
> +assert(rw_fd.fd >= 0);
> +truncfd = rw_fd.fd;
>  }
>  
>  saverr = drop_security_capability(lo, truncfd);
>  if (saverr) {
> -if (!fi) {
> -close(truncfd);
> -}
>  goto out_err;
>  }
>  
> @@ -935,9 +943,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, 
> struct stat *attr,
>  res = drop_effective_cap("FSETID", _fsetid_dropped);
>  if (res != 0) {
>  saverr = res;
> -if 

[PATCH v4 07/12] virtiofsd: Let lo_inode_open() return a TempFd

2021-09-16 Thread Hanna Reitz
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.

The auto-cleanup is nice, though.  Also, we get a more unified interface
where you always get a TempFd when you need an FD for an lo_inode
(regardless of whether it is an O_PATH FD or a non-O_PATH FD).

Signed-off-by: Hanna Reitz 
---
 tools/virtiofsd/passthrough_ll.c | 156 +++
 1 file changed, 75 insertions(+), 81 deletions(-)

diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index 3bf20b8659..d257eda129 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -293,10 +293,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;
@@ -309,10 +307,8 @@ static __attribute__((unused)) int temp_fd_steal(TempFd 
*temp_fd)
 /**
  * Create a borrowing copy of an existing TempFd.  Note that *to is
  * only valid as long as *from is valid.
- *
- * (TODO: Remove __attribute__ once this is used.)
  */
-static __attribute__((unused)) void temp_fd_copy(const TempFd *from, TempFd 
*to)
+static void temp_fd_copy(const TempFd *from, TempFd *to)
 {
 *to = (TempFd) {
 .fd = from->fd,
@@ -689,9 +685,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)
+ int open_flags, TempFd *tfd)
 {
 g_autofree char *fd_str = g_strdup_printf("%d", inode->fd);
 int fd;
@@ -710,7 +709,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)
@@ -854,7 +859,8 @@ static int lo_fi_fd(fuse_req_t req, struct fuse_file_info 
*fi)
 static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int valid, struct fuse_file_info *fi)
 {
-g_auto(TempFd) path_fd = TEMP_FD_INIT;
+g_auto(TempFd) path_fd = TEMP_FD_INIT; /* at least an O_PATH fd */
+g_auto(TempFd) rw_fd = TEMP_FD_INIT; /* O_RDWR fd */
 int saverr;
 char procname[64];
 struct lo_data *lo = lo_data(req);
@@ -868,7 +874,15 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, 
struct stat *attr,
 return;
 }
 
-res = lo_inode_fd(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, _fd);
+if (res >= 0) {
+temp_fd_copy(_fd, _fd);
+}
+} else {
+res = lo_inode_fd(inode, _fd);
+}
 if (res < 0) {
 saverr = -res;
 goto out_err;
@@ -916,18 +930,12 @@ 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;
-}
+assert(rw_fd.fd >= 0);
+truncfd = rw_fd.fd;
 }
 
 saverr = drop_security_capability(lo, truncfd);
 if (saverr) {
-if (!fi) {
-close(truncfd);
-}
 goto out_err;
 }
 
@@ -935,9 +943,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, 
struct stat *attr,
 res = drop_effective_cap("FSETID", _fsetid_dropped);
 if (res != 0) {
 saverr = res;
-if (!fi) {
-close(truncfd);
-}
 goto out_err;
 }
 }
@@ -950,9 +955,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;
 }
@@ -1840,11 +1842,13 @@ 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)
 {
+