fuse: listxattr: verify xattr list
authorMiklos Szeredi <mszeredi@redhat.com>
Sat, 1 Oct 2016 05:32:32 +0000 (07:32 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 22 Oct 2016 10:26:55 +0000 (12:26 +0200)
commit cb3ae6d25a5471be62bfe6ac1fccc0e91edeaba0 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/fuse/dir.c

index 5e2e08712d3ba614a46687d5688fc2f01cd835be..67c0d1046c614469be9bcea332aa07cec6e831b0 100644 (file)
@@ -1797,6 +1797,23 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
        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);
@@ -1832,6 +1849,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;