Commit b24e7598 authored by Miklos Szeredi's avatar Miklos Szeredi

fuse: flush dirty data/metadata before non-truncate setattr

If writeback cache is enabled, then writes might get reordered with
chmod/chown/utimes.  The problem with this is that performing the write in
the fuse daemon might itself change some of these attributes.  In such case
the following sequence of operations will result in file ending up with the
wrong mode, for example:

  int fd = open ("suid", O_WRONLY|O_CREAT|O_EXCL);
  write (fd, "1", 1);
  fchown (fd, 0, 0);
  fchmod (fd, 04755);
  close (fd);

This patch fixes this by flushing pending writes before performing
chown/chmod/utimes.
Reported-by: default avatarGiuseppe Scrivano <gscrivan@redhat.com>
Tested-by: default avatarGiuseppe Scrivano <gscrivan@redhat.com>
Fixes: 4d99ff8f ("fuse: Turn writeback cache on")
Cc: <stable@vger.kernel.org> # v3.15+
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 80da5a80
...@@ -1522,6 +1522,19 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, ...@@ -1522,6 +1522,19 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
is_truncate = true; is_truncate = true;
} }
/* Flush dirty data/metadata before non-truncate SETATTR */
if (is_wb && S_ISREG(inode->i_mode) &&
attr->ia_valid &
(ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_MTIME_SET |
ATTR_TIMES_SET)) {
err = write_inode_now(inode, true);
if (err)
return err;
fuse_set_nowrite(inode);
fuse_release_nowrite(inode);
}
if (is_truncate) { if (is_truncate) {
fuse_set_nowrite(inode); fuse_set_nowrite(inode);
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment