Author: fsu
Date: Tue Aug 21 18:39:47 2018
New Revision: 338152
URL: https://svnweb.freebsd.org/changeset/base/338152

Log:
  FUSE extattrs: fix issue when neither uio nor size were not passed to VOP_*.
  
  The requested size was returned incorrectly in case uio == NULL from 
listextattr because the
  nameprefix/name conversion was not applied.
  Also, make a_size/uio returning logic more unified with other filesystems.
  
  Reviewed by:    cem, pfg
  MFC after:      2 weeks
  
  Differential Revision:        https://reviews.freebsd.org/D13528

Modified:
  head/sys/fs/fuse/fuse_kernel.h
  head/sys/fs/fuse/fuse_vnops.c

Modified: head/sys/fs/fuse/fuse_kernel.h
==============================================================================
--- head/sys/fs/fuse/fuse_kernel.h      Tue Aug 21 18:39:29 2018        
(r338151)
+++ head/sys/fs/fuse/fuse_kernel.h      Tue Aug 21 18:39:47 2018        
(r338152)
@@ -282,11 +282,16 @@ struct fuse_fsync_in {
        __u32   padding;
 };
 
-struct fuse_setxattr_in {
+struct fuse_listxattr_in {
        __u32   size;
        __u32   flags;
 };
 
+struct fuse_listxattr_out {
+       __u32   size;
+       __u32   flags;
+};
+
 struct fuse_getxattr_in {
        __u32   size;
        __u32   padding;
@@ -295,6 +300,11 @@ struct fuse_getxattr_in {
 struct fuse_getxattr_out {
        __u32   size;
        __u32   padding;
+};
+
+struct fuse_setxattr_in {
+       __u32   size;
+       __u32   flags;
 };
 
 struct fuse_lk_in {

Modified: head/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- head/sys/fs/fuse/fuse_vnops.c       Tue Aug 21 18:39:29 2018        
(r338151)
+++ head/sys/fs/fuse/fuse_vnops.c       Tue Aug 21 18:39:47 2018        
(r338152)
@@ -2047,7 +2047,7 @@ fuse_vnop_getextattr(struct vop_getextattr_args *ap)
         * fuse_getxattr_out.  If we pass in a non-zero size, we get back
         * that much data, without the struct fuse_getxattr_out header.
         */
-       if (ap->a_size != NULL)
+       if (uio == NULL)
                get_xattr_in->size = 0;
        else
                get_xattr_in->size = uio->uio_resid;
@@ -2065,25 +2065,13 @@ fuse_vnop_getextattr(struct vop_getextattr_args *ap)
                goto out;
        }
 
-       /*
-        * If we get to this point (i.e. no error), we should have a valid
-        * answer of some sort.  i.e. non-zero iosize and a valid pointer.
-        */
-       if ((fdi.answ == NULL) || (fdi.iosize == 0)) {
-               debug_printf("getxattr: err = 0, but answ = %p, iosize = %zu\n",
-                   fdi.answ, fdi.iosize);
-               err = EINVAL;
-               goto out;
-       }
        get_xattr_out = fdi.answ;
 
-       if (ap->a_size != NULL) {
+       if (ap->a_size != NULL)
                *ap->a_size = get_xattr_out->size;
-       } else if (fdi.iosize > 0) {
+
+       if (uio != NULL)
                err = uiomove(fdi.answ, fdi.iosize, uio);
-       } else {
-               err = EINVAL;
-       }
 
 out:
        fdisp_destroy(&fdi);
@@ -2233,14 +2221,16 @@ fuse_vnop_listextattr(struct vop_listextattr_args *ap)
        struct vnode *vp = ap->a_vp;
        struct uio *uio = ap->a_uio;
        struct fuse_dispatcher fdi = {0};
-       struct fuse_getxattr_in *get_xattr_in;
-       struct fuse_getxattr_out *get_xattr_out;
+       struct fuse_listxattr_in *list_xattr_in;
+       struct fuse_listxattr_out *list_xattr_out;
        struct mount *mp = vnode_mount(vp);
        size_t len;
        char *prefix;
        char *attr_str;
        char *bsd_list = NULL;
+       char *linux_list;
        int bsd_list_len;
+       int linux_list_len;
        struct thread *td = ap->a_td;
        struct ucred *cred = ap->a_cred;
        int err = 0;
@@ -2261,17 +2251,15 @@ fuse_vnop_listextattr(struct vop_listextattr_args *ap)
 
        len = strlen(prefix) + sizeof(extattr_namespace_separator) + 1;
 
-       fdisp_init(&fdi, sizeof(*get_xattr_in) + len);
+       fdisp_init(&fdi, sizeof(*list_xattr_in) + len);
        fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
 
-       get_xattr_in = fdi.indata;
-       if (ap->a_size != NULL)
-               get_xattr_in->size = 0;
-       else
-               get_xattr_in->size = uio->uio_resid + sizeof(*get_xattr_out);
-
-
-       attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
+       /*
+        * Retrieve Linux / FUSE compatible list size.
+        */
+       list_xattr_in = fdi.indata;
+       list_xattr_in->size = 0;
+       attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
        snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
 
        err = fdisp_wait_answ(&fdi);
@@ -2282,32 +2270,47 @@ fuse_vnop_listextattr(struct vop_listextattr_args *ap)
                goto out;
        }
 
-       if ((fdi.answ == NULL) || (fdi.iosize == 0)) {
-               err = EINVAL;
+       list_xattr_out = fdi.answ;
+       linux_list_len = list_xattr_out->size;
+       if (linux_list_len == 0) {
+               if (ap->a_size != NULL)
+                       *ap->a_size = linux_list_len;
                goto out;
        }
-       get_xattr_out = fdi.answ;
 
-       if (ap->a_size != NULL) {
-               *ap->a_size = get_xattr_out->size;
-       } else if (fdi.iosize > 0) {
-               /*
-                * The Linux / FUSE attribute list format isn't the same
-                * as FreeBSD's format.  So we need to transform it into
-                * FreeBSD's format before giving it to the user.
-                */
-               bsd_list = malloc(fdi.iosize, M_TEMP, M_WAITOK);
-               err = fuse_xattrlist_convert(prefix, fdi.answ, fdi.iosize,
-                   bsd_list, &bsd_list_len);
-               if (err != 0)
-                       goto out;
+       /*
+        * Retrieve Linux / FUSE compatible list values.
+        */
+       fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
+       list_xattr_in = fdi.indata;
+       list_xattr_in->size = linux_list_len + sizeof(*list_xattr_out);
+       attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
+       snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
 
+       err = fdisp_wait_answ(&fdi);
+       if (err != 0)
+               goto out;
+
+       linux_list = fdi.answ;
+       linux_list_len = fdi.iosize;
+
+       /*
+        * Retrieve the BSD compatible list values.
+        * The Linux / FUSE attribute list format isn't the same
+        * as FreeBSD's format. So we need to transform it into
+        * FreeBSD's format before giving it to the user.
+        */
+       bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
+       err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
+           bsd_list, &bsd_list_len);
+       if (err != 0)
+               goto out;
+
+       if (ap->a_size != NULL)
+               *ap->a_size = bsd_list_len;
+
+       if (uio != NULL)
                err = uiomove(bsd_list, bsd_list_len, uio);
-       } else {
-               debug_printf("listextattr: returned iosize %zu for %s attribute 
list is "
-                   "too small\n", fdi.iosize, prefix);
-               err = EINVAL;
-       }
 
 out:
        free(bsd_list, M_TEMP);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to