Skip to content

Commit

Permalink
fuse: flush dirty data/metadata before non-truncate setattr
Browse files Browse the repository at this point in the history
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: Giuseppe Scrivano <gscrivan@redhat.com>
Tested-by: Giuseppe Scrivano <gscrivan@redhat.com>
Fixes: 4d99ff8 ("fuse: Turn writeback cache on")
Cc: <stable@vger.kernel.org> # v3.15+
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  • Loading branch information
Miklos Szeredi committed Oct 23, 2019
1 parent 80da5a8 commit b24e759
Showing 1 changed file with 13 additions and 0 deletions.
13 changes: 13 additions & 0 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,19 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
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) {
fuse_set_nowrite(inode);
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
Expand Down

0 comments on commit b24e759

Please sign in to comment.