Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp3176991pxb; Mon, 9 Nov 2020 04:53:55 -0800 (PST) X-Google-Smtp-Source: ABdhPJxTULojr+UvMDLQyyT9TE1o95wSq1rKX4jFbz23c/36Tg1hogNinLPBVgkP1VluN+dCFoCM X-Received: by 2002:a05:6402:181a:: with SMTP id g26mr15882099edy.8.1604926435630; Mon, 09 Nov 2020 04:53:55 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1604926435; cv=none; d=google.com; s=arc-20160816; b=Ha2+SpJuQg7sGVrXxaiIl/0AZNlUNmreQ8sgq3LjY2133FLckPe6tI8E/D6u1Fj5u3 z3v2aZ6w7NsvSytuNNTv8qRIPOhLAWyK1LlMEgEFzqlAFKi4eZp+9ak6TIqlLn9V0t+t nfRAZlVYTt/CceApLHCDhO1ZsRyn9HGlX7C3EXZum96TV+zxZCtq+Vz3vFT64v/68BH+ MCkbWAH/+L1ZZXf0FmKDvZUdDlp147AUDNOjBAXNDnv3iupe2JaqJVuxB5kvrdBX3w8v ONPamo++Vey2jrEY8hCd661r/25bXJ5nQ7FdlJ5oPqoCrU04Kvk/hU26RaAgoP497VYx fuGg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=I0UUTbk++VYKJrf2sroS6pNZ5Xj7SESC9A4oql5gEPc=; b=UeYShiQUezwTY9RrU0CHYpHLJuu3MMcyBoP0ocXRxvfhMADYjaezjFQDX05ug+xtaT nQ/1gUz/L2JCKQpyIRMuKZXGYgSdLy81qPpClG0WP5Ya92uOX9msNzLyOGFQesX1lLWZ hxbkVcJS2ensIGH76X49qRcplMTxZJIyZPWnkidCvBqS2SS0qrRMagdFodZo1nTnPHOw 8SpWP/enR3nTnRm/eEPtXA6lYuF7KDXOwFoIKusRWs7ReCVeKro9UIdBGnNigbvopA3M BVfd1PBX0wmsMimrsKhXBsb5sgUmWMdWZcUtShw03eNW/3maP/c3cyZvkeuG9zdfu2Wv fZnQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c6si7170449edw.204.2020.11.09.04.53.31; Mon, 09 Nov 2020 04:53:55 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729451AbgKIMuE (ORCPT + 99 others); Mon, 9 Nov 2020 07:50:04 -0500 Received: from raptor.unsafe.ru ([5.9.43.93]:53676 "EHLO raptor.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729585AbgKIMtt (ORCPT ); Mon, 9 Nov 2020 07:49:49 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (ip-89-103-122-167.net.upcbroadband.cz [89.103.122.167]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by raptor.unsafe.ru (Postfix) with ESMTPSA id 23C7420A04; Mon, 9 Nov 2020 12:48:22 +0000 (UTC) From: Alexey Gladkov To: LKML , linux-fsdevel@vger.kernel.org Cc: Alexey Gladkov , Miklos Szeredi , "Eric W. Biederman" Subject: [RESEND PATCH v3] fuse: Abort waiting for a response if the daemon receives a fatal signal Date: Mon, 9 Nov 2020 13:46:55 +0100 Message-Id: <1e796f9e008fb78fb96358ff74f39bd4865a7c88.1604926010.git.gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.25.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.1 (raptor.unsafe.ru [5.9.43.93]); Mon, 09 Nov 2020 12:48:25 +0000 (UTC) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch removes one kind of the deadlocks inside the fuse daemon. The problem appear when the fuse daemon itself makes a file operation on its filesystem and receives a fatal signal. This deadlock can be interrupted via fusectl filesystem. But if you have many fuse mountpoints, it will be difficult to figure out which connection to break. This patch aborts the connection if the fuse server receives a fatal signal. Reproducer: https://github.com/sargun/fuse-example Reference: CVE-2019-20794 Fixes: 51eb01e73599 ("[PATCH] fuse: no backgrounding on interrupt") Сс: Andrew Morton Cc: Miklos Szeredi Cc: "Eric W. Biederman" Acked-by: "Eric W. Biederman" Signed-off-by: Alexey Gladkov --- fs/fuse/dev.c | 26 +++++++++++++++++++++++++- fs/fuse/fuse_i.h | 6 ++++++ fs/fuse/inode.c | 3 +++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 02b3c36b3676..eadfed675791 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -21,6 +21,7 @@ #include #include #include +#include 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) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 740a8a7d7ae6..ee9986b3c932 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -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; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index bba747520e9b..8dc86e5079e6 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -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; -- 2.25.4