Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a2abf99 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

fuse: add FUSE_WRITE_KILL_PRIV



In the FOPEN_DIRECT_IO case the write path doesn't call file_remove_privs()
and that means setuid bit is not cleared if unpriviliged user writes to a
file with setuid bit set.

pjdfstest chmod test 12.t tests this and fails.

Fix this by adding a flag to the FUSE_WRITE message that requests clearing
privileges on the given file.  This needs 

This better than just calling fuse_remove_privs(), because the attributes
may not be up to date, so in that case a write may miss clearing the
privileges.

Test case:

  $ passthrough_ll /mnt/pasthrough-mnt -o default_permissions,allow_other,cache=never
  $ mkdir /mnt/pasthrough-mnt/testdir
  $ cd /mnt/pasthrough-mnt/testdir
  $ prove -rv pjdfstests/tests/chmod/12.t

Reported-by: default avatarVivek Goyal <vgoyal@redhat.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
Tested-by: default avatarVivek Goyal <vgoyal@redhat.com>
parent 35d6fcbb
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -1377,10 +1377,17 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
		if (err && !nbytes)
			break;

		if (write)
		if (write) {
			if (!capable(CAP_FSETID)) {
				struct fuse_write_in *inarg;

				inarg = &req->misc.write.in;
				inarg->write_flags |= FUSE_WRITE_KILL_PRIV;
			}
			nres = fuse_send_write(req, io, pos, nbytes, owner);
		else
		} else {
			nres = fuse_send_read(req, io, pos, nbytes, owner);
		}

		if (!io->async)
			fuse_release_user_pages(req, io->should_dirty);
+6 −1
Original line number Diff line number Diff line
@@ -130,6 +130,9 @@
 *  7.30
 *  - add FUSE_EXPLICIT_INVAL_DATA
 *  - add FUSE_IOCTL_COMPAT_X32
 *
 *  7.31
 *  - add FUSE_WRITE_KILL_PRIV flag
 */

#ifndef _LINUX_FUSE_H
@@ -165,7 +168,7 @@
#define FUSE_KERNEL_VERSION 7

/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 30
#define FUSE_KERNEL_MINOR_VERSION 31

/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -327,9 +330,11 @@ struct fuse_file_lock {
 *
 * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
 * FUSE_WRITE_LOCKOWNER: lock_owner field is valid
 * FUSE_WRITE_KILL_PRIV: kill suid and sgid bits
 */
#define FUSE_WRITE_CACHE	(1 << 0)
#define FUSE_WRITE_LOCKOWNER	(1 << 1)
#define FUSE_WRITE_KILL_PRIV	(1 << 2)

/**
 * Read flags