Luis Henriques 68a287
From: Miklos Szeredi <mszeredi@redhat.com>
Luis Henriques 68a287
Date: Thu, 10 Dec 2020 15:33:14 +0100
Luis Henriques 68a287
Subject: fuse: fix bad inode
Luis Henriques 68a287
Git-commit: 5d069dbe8aaf2a197142558b6fb2978189ba3454
Luis Henriques 68a287
Patch-mainline: v5.11-rc1
Luis Henriques 6ecd48
References: bsc#1184211 CVE-2020-36322
Luis Henriques 68a287
Luis Henriques 68a287
Jan Kara's analysis of the syzbot report (edited):
Luis Henriques 68a287
Luis Henriques 68a287
  The reproducer opens a directory on FUSE filesystem, it then attaches
Luis Henriques 68a287
  dnotify mark to the open directory.  After that a fuse_do_getattr() call
Luis Henriques 68a287
  finds that attributes returned by the server are inconsistent, and calls
Luis Henriques 68a287
  make_bad_inode() which, among other things does:
Luis Henriques 68a287
Luis Henriques 68a287
          inode->i_mode = S_IFREG;
Luis Henriques 68a287
Luis Henriques 68a287
  This then confuses dnotify which doesn't tear down its structures
Luis Henriques 68a287
  properly and eventually crashes.
Luis Henriques 68a287
Luis Henriques 68a287
Avoid calling make_bad_inode() on a live inode: switch to a private flag on
Luis Henriques 68a287
the fuse inode.  Also add the test to ops which the bad_inode_ops would
Luis Henriques 68a287
have caught.
Luis Henriques 68a287
Luis Henriques 68a287
This bug goes back to the initial merge of fuse in 2.6.14...
Luis Henriques 68a287
Luis Henriques 68a287
Reported-by: syzbot+f427adf9324b92652ccc@syzkaller.appspotmail.com
Luis Henriques 68a287
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Luis Henriques 68a287
Tested-by: Jan Kara <jack@suse.cz>
Luis Henriques 68a287
Cc: <stable@vger.kernel.org>
Luis Henriques 68a287
[luis:
Luis Henriques 68a287
 - Adjust context
Luis Henriques 68a287
 - Modify fuse_readpages() instead of fuse_readahead() since we don't have
Luis Henriques 68a287
   commit 76a0294eb19b ("fuse: convert from readpages to readahead")]
Luis Henriques 68a287
Acked-by: Luis Henriques <lhenriques@suse.com>
Luis Henriques 68a287
---
Luis Henriques 68a287
 fs/fuse/acl.c     |    6 ++++++
Luis Henriques 68a287
 fs/fuse/dir.c     |   37 ++++++++++++++++++++++++++++++++-----
Luis Henriques 68a287
 fs/fuse/file.c    |   19 +++++++++++--------
Luis Henriques 68a287
 fs/fuse/fuse_i.h  |   12 ++++++++++++
Luis Henriques 68a287
 fs/fuse/inode.c   |    4 ++--
Luis Henriques 68a287
 fs/fuse/readdir.c |    4 ++--
Luis Henriques 68a287
 fs/fuse/xattr.c   |    9 +++++++++
Luis Henriques 68a287
 7 files changed, 74 insertions(+), 17 deletions(-)
Luis Henriques 68a287
Luis Henriques 68a287
--- a/fs/fuse/acl.c
Luis Henriques 68a287
+++ b/fs/fuse/acl.c
Luis Henriques 68a287
@@ -19,6 +19,9 @@ struct posix_acl *fuse_get_acl(struct in
Luis Henriques 68a287
 	void *value = NULL;
Luis Henriques 68a287
 	struct posix_acl *acl;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return ERR_PTR(-EIO);
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (!fc->posix_acl || fc->no_getxattr)
Luis Henriques 68a287
 		return NULL;
Luis Henriques 68a287
 
Luis Henriques 68a287
@@ -53,6 +56,9 @@ int fuse_set_acl(struct inode *inode, st
Luis Henriques 68a287
 	const char *name;
Luis Henriques 68a287
 	int ret;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (!fc->posix_acl || fc->no_setxattr)
Luis Henriques 68a287
 		return -EOPNOTSUPP;
Luis Henriques 68a287
 
Luis Henriques 68a287
--- a/fs/fuse/dir.c
Luis Henriques 68a287
+++ b/fs/fuse/dir.c
Luis Henriques 68a287
@@ -167,7 +167,7 @@ static int fuse_dentry_revalidate(struct
Luis Henriques 68a287
 	int ret;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	inode = d_inode_rcu(entry);
Luis Henriques 68a287
-	if (inode && is_bad_inode(inode))
Luis Henriques 68a287
+	if (inode && fuse_is_bad(inode))
Luis Henriques 68a287
 		goto invalid;
Luis Henriques 68a287
 	else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
Luis Henriques 68a287
 		 (flags & LOOKUP_REVAL)) {
Luis Henriques 68a287
@@ -339,6 +339,9 @@ static struct dentry *fuse_lookup(struct
Luis Henriques 68a287
 	bool outarg_valid = true;
Luis Henriques 68a287
 	bool locked;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(dir))
Luis Henriques 68a287
+		return ERR_PTR(-EIO);
Luis Henriques 68a287
+
Luis Henriques 68a287
 	locked = fuse_lock_inode(dir);
Luis Henriques 68a287
 	err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
Luis Henriques 68a287
 			       &outarg, &inode;;
Luis Henriques 68a287
@@ -481,6 +484,9 @@ static int fuse_atomic_open(struct inode
Luis Henriques 68a287
 	struct fuse_conn *fc = get_fuse_conn(dir);
Luis Henriques 68a287
 	struct dentry *res = NULL;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(dir))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (d_in_lookup(entry)) {
Luis Henriques 68a287
 		res = fuse_lookup(dir, entry, 0);
Luis Henriques 68a287
 		if (IS_ERR(res))
Luis Henriques 68a287
@@ -529,6 +535,9 @@ static int create_new_entry(struct fuse_
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 	struct fuse_forget_link *forget;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(dir))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	forget = fuse_alloc_forget();
Luis Henriques 68a287
 	if (!forget)
Luis Henriques 68a287
 		return -ENOMEM;
Luis Henriques 68a287
@@ -656,6 +665,9 @@ static int fuse_unlink(struct inode *dir
Luis Henriques 68a287
 	struct fuse_conn *fc = get_fuse_conn(dir);
Luis Henriques 68a287
 	FUSE_ARGS(args);
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(dir))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	args.in.h.opcode = FUSE_UNLINK;
Luis Henriques 68a287
 	args.in.h.nodeid = get_node_id(dir);
Luis Henriques 68a287
 	args.in.numargs = 1;
Luis Henriques 68a287
@@ -692,6 +704,9 @@ static int fuse_rmdir(struct inode *dir,
Luis Henriques 68a287
 	struct fuse_conn *fc = get_fuse_conn(dir);
Luis Henriques 68a287
 	FUSE_ARGS(args);
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(dir))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	args.in.h.opcode = FUSE_RMDIR;
Luis Henriques 68a287
 	args.in.h.nodeid = get_node_id(dir);
Luis Henriques 68a287
 	args.in.numargs = 1;
Luis Henriques 68a287
@@ -770,6 +785,9 @@ static int fuse_rename2(struct inode *ol
Luis Henriques 68a287
 	struct fuse_conn *fc = get_fuse_conn(olddir);
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(olddir))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
Luis Henriques 68a287
 		return -EINVAL;
Luis Henriques 68a287
 
Luis Henriques 68a287
@@ -905,7 +923,7 @@ static int fuse_do_getattr(struct inode
Luis Henriques 68a287
 	if (!err) {
Luis Henriques 68a287
 		if (fuse_invalid_attr(&outarg.attr) ||
Luis Henriques 68a287
 		    (inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Luis Henriques 68a287
-			make_bad_inode(inode);
Luis Henriques 68a287
+			fuse_make_bad(inode);
Luis Henriques 68a287
 			err = -EIO;
Luis Henriques 68a287
 		} else {
Luis Henriques 68a287
 			fuse_change_attributes(inode, &outarg.attr,
Luis Henriques 68a287
@@ -1107,6 +1125,9 @@ static int fuse_permission(struct inode
Luis Henriques 68a287
 	bool refreshed = false;
Luis Henriques 68a287
 	int err = 0;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (!fuse_allow_current_process(fc))
Luis Henriques 68a287
 		return -EACCES;
Luis Henriques 68a287
 
Luis Henriques 68a287
@@ -1204,7 +1225,7 @@ static const char *fuse_get_link(struct
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	err = -EIO;
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		goto out_err;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	if (fc->cache_symlinks)
Luis Henriques 68a287
@@ -1252,7 +1273,7 @@ static int fuse_dir_fsync(struct file *f
Luis Henriques 68a287
 	struct fuse_conn *fc = get_fuse_conn(inode);
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		return -EIO;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	if (fc->no_fsyncdir)
Luis Henriques 68a287
@@ -1529,7 +1550,7 @@ int fuse_do_setattr(struct dentry *dentr
Luis Henriques 68a287
 
Luis Henriques 68a287
 	if (fuse_invalid_attr(&outarg.attr) ||
Luis Henriques 68a287
 	    (inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Luis Henriques 68a287
-		make_bad_inode(inode);
Luis Henriques 68a287
+		fuse_make_bad(inode);
Luis Henriques 68a287
 		err = -EIO;
Luis Henriques 68a287
 		goto error;
Luis Henriques 68a287
 	}
Luis Henriques 68a287
@@ -1585,6 +1606,9 @@ static int fuse_setattr(struct dentry *e
Luis Henriques 68a287
 	struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL;
Luis Henriques 68a287
 	int ret;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (!fuse_allow_current_process(get_fuse_conn(inode)))
Luis Henriques 68a287
 		return -EACCES;
Luis Henriques 68a287
 
Luis Henriques 68a287
@@ -1643,6 +1667,9 @@ static int fuse_getattr(const struct pat
Luis Henriques 68a287
 	struct inode *inode = d_inode(path->dentry);
Luis Henriques 68a287
 	struct fuse_conn *fc = get_fuse_conn(inode);
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (!fuse_allow_current_process(fc))
Luis Henriques 68a287
 		return -EACCES;
Luis Henriques 68a287
 
Luis Henriques 68a287
--- a/fs/fuse/file.c
Luis Henriques 68a287
+++ b/fs/fuse/file.c
Luis Henriques 68a287
@@ -206,6 +206,9 @@ int fuse_open_common(struct inode *inode
Luis Henriques 68a287
 			  fc->atomic_o_trunc &&
Luis Henriques 68a287
 			  fc->writeback_cache;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	err = generic_file_open(inode, file);
Luis Henriques 68a287
 	if (err)
Luis Henriques 68a287
 		return err;
Luis Henriques 68a287
@@ -420,7 +423,7 @@ static int fuse_flush(struct file *file,
Luis Henriques 68a287
 	struct fuse_flush_in inarg;
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		return -EIO;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	if (fc->no_flush)
Luis Henriques 68a287
@@ -485,7 +488,7 @@ static int fuse_fsync(struct file *file,
Luis Henriques 68a287
 	struct fuse_conn *fc = get_fuse_conn(inode);
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		return -EIO;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	inode_lock(inode);
Luis Henriques 68a287
@@ -784,7 +787,7 @@ static int fuse_readpage(struct file *fi
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	err = -EIO;
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		goto out;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	err = fuse_do_readpage(file, page);
Luis Henriques 68a287
@@ -911,7 +914,7 @@ static int fuse_readpages(struct file *f
Luis Henriques 68a287
 	unsigned int nr_alloc = min_t(unsigned int, nr_pages, fc->max_pages);
Luis Henriques 68a287
 
Luis Henriques 68a287
 	err = -EIO;
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		goto out;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	data.file = file;
Luis Henriques 68a287
@@ -1497,7 +1500,7 @@ static ssize_t fuse_file_read_iter(struc
Luis Henriques 68a287
 	struct file *file = iocb->ki_filp;
Luis Henriques 68a287
 	struct fuse_file *ff = file->private_data;
Luis Henriques 68a287
 
Luis Henriques 68a287
-	if (is_bad_inode(file_inode(file)))
Luis Henriques 68a287
+	if (fuse_is_bad(file_inode(file)))
Luis Henriques 68a287
 		return -EIO;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	if (!(ff->open_flags & FOPEN_DIRECT_IO))
Luis Henriques 68a287
@@ -1511,7 +1514,7 @@ static ssize_t fuse_file_write_iter(stru
Luis Henriques 68a287
 	struct file *file = iocb->ki_filp;
Luis Henriques 68a287
 	struct fuse_file *ff = file->private_data;
Luis Henriques 68a287
 
Luis Henriques 68a287
-	if (is_bad_inode(file_inode(file)))
Luis Henriques 68a287
+	if (fuse_is_bad(file_inode(file)))
Luis Henriques 68a287
 		return -EIO;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	if (!(ff->open_flags & FOPEN_DIRECT_IO))
Luis Henriques 68a287
@@ -1997,7 +2000,7 @@ static int fuse_writepages(struct addres
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	err = -EIO;
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		goto out;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	data.inode = inode;
Luis Henriques 68a287
@@ -2787,7 +2790,7 @@ long fuse_ioctl_common(struct file *file
Luis Henriques 68a287
 	if (!fuse_allow_current_process(fc))
Luis Henriques 68a287
 		return -EACCES;
Luis Henriques 68a287
 
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		return -EIO;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	return fuse_do_ioctl(file, cmd, arg, flags);
Luis Henriques 68a287
--- a/fs/fuse/fuse_i.h
Luis Henriques 68a287
+++ b/fs/fuse/fuse_i.h
Luis Henriques 68a287
@@ -161,6 +161,8 @@ enum {
Luis Henriques 68a287
 	FUSE_I_INIT_RDPLUS,
Luis Henriques 68a287
 	/** An operation changing file size is in progress  */
Luis Henriques 68a287
 	FUSE_I_SIZE_UNSTABLE,
Luis Henriques 68a287
+	/* Bad inode */
Luis Henriques 68a287
+	FUSE_I_BAD,
Luis Henriques 68a287
 };
Luis Henriques 68a287
 
Luis Henriques 68a287
 struct fuse_conn;
Luis Henriques 68a287
@@ -794,6 +796,16 @@ static inline u64 fuse_get_attr_version(
Luis Henriques 68a287
 	return atomic64_read(&fc->attr_version);
Luis Henriques 68a287
 }
Luis Henriques 68a287
 
Luis Henriques 68a287
+static inline void fuse_make_bad(struct inode *inode)
Luis Henriques 68a287
+{
Luis Henriques 68a287
+	set_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state);
Luis Henriques 68a287
+}
Luis Henriques 68a287
+
Luis Henriques 68a287
+static inline bool fuse_is_bad(struct inode *inode)
Luis Henriques 68a287
+{
Luis Henriques 68a287
+	return unlikely(test_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state));
Luis Henriques 68a287
+}
Luis Henriques 68a287
+
Luis Henriques 68a287
 /** Device operations */
Luis Henriques 68a287
 extern const struct file_operations fuse_dev_operations;
Luis Henriques 68a287
 
Luis Henriques 68a287
--- a/fs/fuse/inode.c
Luis Henriques 68a287
+++ b/fs/fuse/inode.c
Luis Henriques 68a287
@@ -125,7 +125,7 @@ static void fuse_evict_inode(struct inod
Luis Henriques 68a287
 		fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup);
Luis Henriques 68a287
 		fi->forget = NULL;
Luis Henriques 68a287
 	}
Luis Henriques 68a287
-	if (S_ISREG(inode->i_mode) && !is_bad_inode(inode)) {
Luis Henriques 68a287
+	if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) {
Luis Henriques 68a287
 		WARN_ON(!list_empty(&fi->write_files));
Luis Henriques 68a287
 		WARN_ON(!list_empty(&fi->queued_writes));
Luis Henriques 68a287
 	}
Luis Henriques 68a287
@@ -314,7 +314,7 @@ struct inode *fuse_iget(struct super_blo
Luis Henriques 68a287
 		unlock_new_inode(inode);
Luis Henriques 68a287
 	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
Luis Henriques 68a287
 		/* Inode has changed type, any I/O on the old should fail */
Luis Henriques 68a287
-		make_bad_inode(inode);
Luis Henriques 68a287
+		fuse_make_bad(inode);
Luis Henriques 68a287
 		iput(inode);
Luis Henriques 68a287
 		goto retry;
Luis Henriques 68a287
 	}
Luis Henriques 68a287
--- a/fs/fuse/readdir.c
Luis Henriques 68a287
+++ b/fs/fuse/readdir.c
Luis Henriques 68a287
@@ -207,7 +207,7 @@ retry:
Luis Henriques 68a287
 			dput(dentry);
Luis Henriques 68a287
 			goto retry;
Luis Henriques 68a287
 		}
Luis Henriques 68a287
-		if (is_bad_inode(inode)) {
Luis Henriques 68a287
+		if (fuse_is_bad(inode)) {
Luis Henriques 68a287
 			dput(dentry);
Luis Henriques 68a287
 			return -EIO;
Luis Henriques 68a287
 		}
Luis Henriques 68a287
@@ -554,7 +554,7 @@ int fuse_readdir(struct file *file, stru
Luis Henriques 68a287
 	struct inode *inode = file_inode(file);
Luis Henriques 68a287
 	int err;
Luis Henriques 68a287
 
Luis Henriques 68a287
-	if (is_bad_inode(inode))
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
 		return -EIO;
Luis Henriques 68a287
 
Luis Henriques 68a287
 	mutex_lock(&ff->readdir.lock);
Luis Henriques 68a287
--- a/fs/fuse/xattr.c
Luis Henriques 68a287
+++ b/fs/fuse/xattr.c
Luis Henriques 68a287
@@ -113,6 +113,9 @@ ssize_t fuse_listxattr(struct dentry *en
Luis Henriques 68a287
 	struct fuse_getxattr_out outarg;
Luis Henriques 68a287
 	ssize_t ret;
Luis Henriques 68a287
 
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (!fuse_allow_current_process(fc))
Luis Henriques 68a287
 		return -EACCES;
Luis Henriques 68a287
 
Luis Henriques 68a287
@@ -178,6 +181,9 @@ static int fuse_xattr_get(const struct x
Luis Henriques 68a287
 			 struct dentry *dentry, struct inode *inode,
Luis Henriques 68a287
 			 const char *name, void *value, size_t size)
Luis Henriques 68a287
 {
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	return fuse_getxattr(inode, name, value, size);
Luis Henriques 68a287
 }
Luis Henriques 68a287
 
Luis Henriques 68a287
@@ -186,6 +192,9 @@ static int fuse_xattr_set(const struct x
Luis Henriques 68a287
 			  const char *name, const void *value, size_t size,
Luis Henriques 68a287
 			  int flags)
Luis Henriques 68a287
 {
Luis Henriques 68a287
+	if (fuse_is_bad(inode))
Luis Henriques 68a287
+		return -EIO;
Luis Henriques 68a287
+
Luis Henriques 68a287
 	if (!value)
Luis Henriques 68a287
 		return fuse_removexattr(inode, name);
Luis Henriques 68a287