summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-10-01 08:32:32 +0300
committerBen Hutchings <ben@decadent.org.uk>2017-02-23 06:54:07 +0300
commitcbe308a4471f9dc65d1059bd2f9e242ddcf4b548 (patch)
treeabac907c7c1303c33532b07d470c7b33dbcfcd79
parent2787db9e6b9600dab0e0aae39d197a3d21c890b5 (diff)
downloadlinux-cbe308a4471f9dc65d1059bd2f9e242ddcf4b548.tar.xz
fuse: listxattr: verify xattr list
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> [bwh: Backported to 3.16: adjust context, indentation] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--fs/fuse/dir.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index d4ba4e1a7fb9..2ef8defac554 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1968,6 +1968,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 = entry->d_inode;
@@ -2006,9 +2023,11 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
}
fuse_request_send(fc, req);
ret = req->out.h.error;
- if (!ret)
+ if (!ret) {
ret = size ? req->out.args[0].size : outarg.size;
- else {
+ if (ret > 0 && size)
+ ret = fuse_verify_xattr_list(list, ret);
+ } else {
if (ret == -ENOSYS) {
fc->no_listxattr = 1;
ret = -EOPNOTSUPP;