@@ -174,10 +174,12 @@ struct fuse_mount;
struct fuse_release_args;
/**
- * Reference to backing file for read/write operations in passthrough mode.
+ * Reference to backing file for read/write operations in passthrough mode
+ * and the credentials to be used for passthrough operations.
*/
struct fuse_passthrough {
struct file *filp;
+ struct cred *cred;
/** refcount */
refcount_t count;
@@ -45,12 +45,14 @@ ssize_t fuse_passthrough_read_iter(struct kiocb *iocb_fuse,
struct file *fuse_filp = iocb_fuse->ki_filp;
struct fuse_file *ff = fuse_filp->private_data;
struct file *passthrough_filp = ff->passthrough->filp;
+ const struct cred *old_cred;
ssize_t ret;
rwf_t rwf;
if (!iov_iter_count(iter))
return 0;
+ old_cred = override_creds(ff->passthrough->cred);
if (is_sync_kiocb(iocb_fuse)) {
rwf = iocb_to_rw_flags(iocb_fuse->ki_flags, FUSE_IOCB_MASK);
ret = vfs_iter_read(passthrough_filp, iter, &iocb_fuse->ki_pos,
@@ -59,8 +61,10 @@ ssize_t fuse_passthrough_read_iter(struct kiocb *iocb_fuse,
struct fuse_aio_req *aio_req;
aio_req = kmalloc(sizeof(struct fuse_aio_req), GFP_KERNEL);
- if (!aio_req)
- return -ENOMEM;
+ if (!aio_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
aio_req->iocb_fuse = iocb_fuse;
kiocb_clone(&aio_req->iocb, iocb_fuse, passthrough_filp);
@@ -69,6 +73,8 @@ ssize_t fuse_passthrough_read_iter(struct kiocb *iocb_fuse,
if (ret != -EIOCBQUEUED)
fuse_aio_cleanup_handler(aio_req);
}
+out:
+ revert_creds(old_cred);
return ret;
}
@@ -81,6 +87,7 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb_fuse,
struct inode *fuse_inode = file_inode(fuse_filp);
struct file *passthrough_filp = ff->passthrough->filp;
struct inode *passthrough_inode = file_inode(passthrough_filp);
+ const struct cred *old_cred;
ssize_t ret;
rwf_t rwf;
@@ -89,6 +96,7 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb_fuse,
inode_lock(fuse_inode);
+ old_cred = override_creds(ff->passthrough->cred);
if (is_sync_kiocb(iocb_fuse)) {
file_start_write(passthrough_filp);
rwf = iocb_to_rw_flags(iocb_fuse->ki_flags, FUSE_IOCB_MASK);
@@ -115,6 +123,7 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb_fuse,
fuse_aio_cleanup_handler(aio_req);
}
out:
+ revert_creds(old_cred);
inode_unlock(fuse_inode);
return ret;
@@ -156,6 +165,7 @@ int fuse_passthrough_open(struct fuse_conn *fc, int backing_fd)
goto out_fput;
passthrough->filp = passthrough_filp;
+ passthrough->cred = prepare_creds();
refcount_set(&passthrough->count, 1);
idr_preload(GFP_KERNEL);
@@ -232,5 +242,9 @@ void fuse_passthrough_free(struct fuse_passthrough *passthrough)
fput(passthrough->filp);
passthrough->filp = NULL;
}
+ if (passthrough->cred) {
+ put_cred(passthrough->cred);
+ passthrough->cred = NULL;
+ }
kfree_rcu(passthrough, rcu);
}