Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Aug 2018 18:39:47 +0000 (UTC)
From:      Fedor Uporov <fsu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r338152 - head/sys/fs/fuse
Message-ID:  <201808211839.w7LIdlFc093336@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808211839.w7LIdlFc093336>