Skip to content

Commit 4a2abf9

Browse files
author
Miklos Szeredi
committed
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: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Tested-by: Vivek Goyal <vgoyal@redhat.com>
1 parent 35d6fcb commit 4a2abf9

File tree

2 files changed

+15
-3
lines changed

2 files changed

+15
-3
lines changed

fs/fuse/file.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,10 +1377,17 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
13771377
if (err && !nbytes)
13781378
break;
13791379

1380-
if (write)
1380+
if (write) {
1381+
if (!capable(CAP_FSETID)) {
1382+
struct fuse_write_in *inarg;
1383+
1384+
inarg = &req->misc.write.in;
1385+
inarg->write_flags |= FUSE_WRITE_KILL_PRIV;
1386+
}
13811387
nres = fuse_send_write(req, io, pos, nbytes, owner);
1382-
else
1388+
} else {
13831389
nres = fuse_send_read(req, io, pos, nbytes, owner);
1390+
}
13841391

13851392
if (!io->async)
13861393
fuse_release_user_pages(req, io->should_dirty);

include/uapi/linux/fuse.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@
130130
* 7.30
131131
* - add FUSE_EXPLICIT_INVAL_DATA
132132
* - add FUSE_IOCTL_COMPAT_X32
133+
*
134+
* 7.31
135+
* - add FUSE_WRITE_KILL_PRIV flag
133136
*/
134137

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

167170
/** Minor version number of this interface */
168-
#define FUSE_KERNEL_MINOR_VERSION 30
171+
#define FUSE_KERNEL_MINOR_VERSION 31
169172

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

334339
/**
335340
* Read flags

0 commit comments

Comments
 (0)