summaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-10-01 07:32:32 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2016-10-01 07:32:32 +0200
commitcb3ae6d25a5471be62bfe6ac1fccc0e91edeaba0 (patch)
tree414245970cef6557f01578bde5649e35aaeb3663 /fs/fuse/dir.c
parentLinux 4.8-rc8 (diff)
downloadlinux-cb3ae6d25a5471be62bfe6ac1fccc0e91edeaba0.tar.xz
linux-cb3ae6d25a5471be62bfe6ac1fccc0e91edeaba0.zip
fuse: listxattr: verify xattr list
Make sure userspace filesystem is returning a well formed list of xattr names (zero or more nonzero length, null terminated strings). [Michael Theall: only verify in the nonzero size case] Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Cc: <stable@vger.kernel.org>
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r--fs/fuse/dir.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index c47b7780ce37..b87c9bcd6306 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1801,6 +1801,23 @@ static ssize_t fuse_getxattr(struct dentry *entry, struct inode *inode,
return ret;
}
+static int fuse_verify_xattr_list(char *list, size_t size)
+{
+ size_t origsize = size;
+
+ while (size) {
+ size_t thislen = strnlen(list, size);
+
+ if (!thislen || thislen == size)
+ return -EIO;
+
+ size -= thislen + 1;
+ list += thislen + 1;
+ }
+
+ return origsize;
+}
+
static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
{
struct inode *inode = d_inode(entry);
@@ -1836,6 +1853,8 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
ret = fuse_simple_request(fc, &args);
if (!ret && !size)
ret = outarg.size;
+ if (ret > 0 && size)
+ ret = fuse_verify_xattr_list(list, ret);
if (ret == -ENOSYS) {
fc->no_listxattr = 1;
ret = -EOPNOTSUPP;