@@ -21,6 +21,7 @@
#include <linux/swap.h>
#include <linux/splice.h>
#include <linux/sched.h>
+#include <linux/fdtable.h>
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
MODULE_ALIAS("devname:fuse");
@@ -357,6 +358,29 @@ static int queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
return 0;
}
+static int match_fusedev(const void *p, struct file *file, unsigned fd)
+{
+ return ((struct fuse_conn *) p)->fusedev_file == file;
+}
+
+static inline bool is_fuse_daemon(struct fuse_conn *fc)
+{
+ return iterate_fd(current->files, 0, match_fusedev, fc);
+}
+
+static inline bool is_conn_untrusted(struct fuse_conn *fc)
+{
+ return (fc->sb->s_iflags & SB_I_UNTRUSTED_MOUNTER);
+}
+
+static inline bool is_event_finished(struct fuse_conn *fc, struct fuse_req *req)
+{
+ if (fc->check_fusedev_file &&
+ fatal_signal_pending(current) && is_conn_untrusted(fc) && is_fuse_daemon(fc))
+ fuse_abort_conn(fc);
+ return test_bit(FR_FINISHED, &req->flags);
+}
+
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
{
struct fuse_iqueue *fiq = &fc->iq;
@@ -399,7 +423,7 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
* Either request is already in userspace, or it was forced.
* Wait it out.
*/
- wait_event(req->waitq, test_bit(FR_FINISHED, &req->flags));
+ wait_event(req->waitq, is_event_finished(fc, req));
}
static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
@@ -516,6 +516,9 @@ struct fuse_conn {
/** The group id for this mount */
kgid_t group_id;
+ /** The /dev/fuse file for this mount */
+ struct file *fusedev_file;
+
/** The pid namespace for this mount */
struct pid_namespace *pid_ns;
@@ -720,6 +723,9 @@ struct fuse_conn {
/* Do not show mount options */
unsigned int no_mount_options:1;
+ /** Do not check fusedev_file (virtiofs) */
+ unsigned int check_fusedev_file:1;
+
/** The number of requests waiting for completion */
atomic_t num_waiting;
@@ -1201,6 +1201,8 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
fc->no_control = ctx->no_control;
fc->no_force_umount = ctx->no_force_umount;
fc->no_mount_options = ctx->no_mount_options;
+ fc->fusedev_file = fget(ctx->fd);
+ fc->check_fusedev_file = 1;
err = -ENOMEM;
root = fuse_get_root_inode(sb, ctx->rootmode);
@@ -1348,6 +1350,7 @@ static void fuse_sb_destroy(struct super_block *sb)
fuse_abort_conn(fc);
fuse_wait_aborted(fc);
+ fput(fc->fusedev_file);
down_write(&fc->killsb);
fc->sb = NULL;