Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3146825imu; Wed, 7 Nov 2018 05:56:18 -0800 (PST) X-Google-Smtp-Source: AJdET5fljWaZzRZBtf6p9y+uBJ5E3qSUJ8KUt+e+MymmYpNCJOqcn2DsH8AoFgt38f3MWSL1PYLq X-Received: by 2002:a62:b87:: with SMTP id 7-v6mr299998pfl.67.1541598978883; Wed, 07 Nov 2018 05:56:18 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541598978; cv=none; d=google.com; s=arc-20160816; b=kdrM7PzZxVyUlB49rVqT9p+UKpaQj96Bq2pb4zlFsTtAN2jRdsmvTv1rZsrVHr1RYe 25HFIwnuMtK43ofZN0tvLIQsCJL5krIZyON0SDmM/VRseFhh0YOeS7jcM3jURVv4Mybo 3RQYhkUR8OP9Kzvr8vp7RBo0y8fIuZdq4sNM4q0KDYMNin81+f1RzZy++45kumOq8b0G 7NlJcKMRaH+3esbkFCshMv3nAvv3Zqe5ybIip2cvVeAbfSeWbLoRPwFypLf2qqpDtQO5 aSgpwZVwDNzyeM3Q69hSsVfB2CLyeVAMej0ZRJPOP2qaLZpQXpHyq3YkmNzf8lQ/MeCZ Oapg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature; bh=FGh01L7cooZqcnHrnmambmA0GV3gC0p/DtcaHT2//s4=; b=gngT3+Nuro/qgFSL1a/VtIKBQma5h5cSZZgGIy7UqdEuabMKIo/aDbBZRtHShvsFrM hoMs6YgEcHQ2aOAPXTrbcXp8jyZATGb3TWXq97IPefZLncXJ3WjhyNaXS/bnkEkHzCxP A65QYw0Jaj+DE+MwBH+N96z7LerEMj7QPlKTpV2tJJ5oW5uykLDZqb47MecY4hdR0rXi DiiPILYaduhkhWJx6JLBHUMQKjVM/jXE659/KDabD+3oxJlXCi8zKgyt/Cj64SffedyN uWQ1FlN2ptqSIBnkUdhR5MxIiJRGOKmWpEwOhmaex0+pznVaWnMlDfBkIHi0ricZsoT/ NUNw== ARC-Authentication-Results: i=1; mx.google.com; dkim=temperror (no key for signature) header.i=@szeredi.hu header.s=google header.b=HOrTghbs; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v33-v6si570349pga.450.2018.11.07.05.56.02; Wed, 07 Nov 2018 05:56:18 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=temperror (no key for signature) header.i=@szeredi.hu header.s=google header.b=HOrTghbs; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727693AbeKGX0F (ORCPT + 99 others); Wed, 7 Nov 2018 18:26:05 -0500 Received: from mail-it1-f196.google.com ([209.85.166.196]:51419 "EHLO mail-it1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726893AbeKGX0F (ORCPT ); Wed, 7 Nov 2018 18:26:05 -0500 Received: by mail-it1-f196.google.com with SMTP id m34-v6so1739826iti.1 for ; Wed, 07 Nov 2018 05:55:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=szeredi.hu; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=FGh01L7cooZqcnHrnmambmA0GV3gC0p/DtcaHT2//s4=; b=HOrTghbscRey9eM5er7N8naaqFu1Hl8dtSgB8b1SxggRlpD2EmkiudI259fqLk4l1h nil6pQg466iWrOdq+DQ7yLRy+6HDKTpHWML2tZLFzpafX7/k2I3L4xjZ1KRlZDZd/Ni2 T/o3EuD7yxf91TGpO8U3ryEdh2Y7spR9D8BhI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=FGh01L7cooZqcnHrnmambmA0GV3gC0p/DtcaHT2//s4=; b=m5X/Yw+ULun1qCZinKjrFElbBzV3AorJhSX6ECfdMrAn5o+fYnoh65BhGiKNn6V8D5 NlAGY4gptt0kA6eloBjBdrhAdkjBP1dZmW4Dz36mq/zPuS46Rrhb8iC0UQJ0+91Szg2a uqt4YNlez8KewG8GLbcH99FvTDqGySsStErrlI3zHTgNz1DrbL1ReA03hFoxqcbVmzxh BtRWviH0MEbcnjnbBa/qLh3lnTd48cG6f3lGACKDp6wW+zOLKpK/OFUAUW761eEvSdw5 AYVtyHRdpL0T8srDij/ATxzfuwl5y/7I9AFDCnZdU/zYp/kxvDYVC3hHRhYw4qG9iFO+ nCEQ== X-Gm-Message-State: AGRZ1gIWMvG+UTHcwVXsvuLk//qduo1ZaqC0+S3mc7kYpw2WRVKGX5fy ztA7TOlj5j8/hZhn/rfXdkac8CEtmP5MF0HOg74gNg== X-Received: by 2002:a24:750f:: with SMTP id y15-v6mr264857itc.1.1541598935418; Wed, 07 Nov 2018 05:55:35 -0800 (PST) MIME-Version: 1.0 Received: by 2002:a6b:ac42:0:0:0:0:0 with HTTP; Wed, 7 Nov 2018 05:55:34 -0800 (PST) X-Originating-IP: [212.96.48.140] In-Reply-To: <154149666097.17764.12092615786683141764.stgit@localhost.localdomain> References: <154149586524.17764.5252013294539109287.stgit@localhost.localdomain> <154149666097.17764.12092615786683141764.stgit@localhost.localdomain> From: Miklos Szeredi Date: Wed, 7 Nov 2018 14:55:34 +0100 Message-ID: Subject: Re: [PATCH 6/6] fuse: Verify userspace asks to requeue interrupt that we really sent To: Kirill Tkhai Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Nov 6, 2018 at 10:31 AM, Kirill Tkhai wrote: > When queue_interrupt() is called from fuse_dev_do_write(), > it came from userspace directly. Userspace may pass any > request id, even the request's we have not interrupted > (or even background's request). This patch adds sanity > check to make kernel safe against that. Okay, I understand this far. > The problem is real interrupt may be queued and requeued > by two tasks on two cpus. This case, the requeuer has not > guarantees it sees FR_INTERRUPTED bit on its cpu (since > we know nothing about the way userspace manages requests > between its threads and whether it uses smp barriers). This sounds like BS. There's an explicit smp_mb__after_atomic() after the set_bit(FR_INTERRUPTED,...). Which means FR_INTERRUPTED is going to be visible on all CPU's after this, no need to fool around with setting FR_INTERRUPTED again, etc... > > To eliminate this problem, queuer writes FR_INTERRUPTED > bit again under fiq->waitq.lock, and this guarantees > requeuer will see the bit, when checks it. > > I try to introduce solution, which does not affect on > performance, and which does not force to take more > locks. This is the reason, the below solution is worse: > > request_wait_answer() > { > ... > + spin_lock(&fiq->waitq.lock); > set_bit(FR_INTERRUPTED, &req->flags); > + spin_unlock(&fiq->waitq.lock); > ... > } > > Also, it does not look a better idea to extend fuse_dev_do_read() > with the fix, since it's already a big function: > > fuse_dev_do_read() > { > ... > if (test_bit(FR_INTERRUPTED, &req->flags)) { > + /* Comment */ > + barrier(); > + set_bit(FR_INTERRUPTED, &req->flags); > queue_interrupt(fiq, req); > } > ... > } > > Signed-off-by: Kirill Tkhai > --- > fs/fuse/dev.c | 26 +++++++++++++++++++++----- > 1 file changed, 21 insertions(+), 5 deletions(-) > > diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c > index 315d395d5c02..3bfc5ed61c9a 100644 > --- a/fs/fuse/dev.c > +++ b/fs/fuse/dev.c > @@ -475,13 +475,27 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) > fuse_put_request(fc, req); > } > > -static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req) > +static int queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req) > { > bool kill = false; > > if (test_bit(FR_FINISHED, &req->flags)) > - return; > + return 0; > spin_lock(&fiq->waitq.lock); > + /* Check for we've sent request to interrupt this req */ > + if (unlikely(!test_bit(FR_INTERRUPTED, &req->flags))) { > + spin_unlock(&fiq->waitq.lock); > + return -EINVAL; > + } > + /* > + * Interrupt may be queued from fuse_dev_do_read(), and > + * later requeued on other cpu by fuse_dev_do_write(). > + * To make FR_INTERRUPTED bit visible for the requeuer > + * (under fiq->waitq.lock) we write it once again. > + */ > + barrier(); > + __set_bit(FR_INTERRUPTED, &req->flags); > + > if (list_empty(&req->intr_entry)) { > list_add_tail(&req->intr_entry, &fiq->interrupts); > /* > @@ -492,7 +506,7 @@ static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req) > if (test_bit(FR_FINISHED, &req->flags)) { > list_del_init(&req->intr_entry); > spin_unlock(&fiq->waitq.lock); > - return; > + return 0; > } > wake_up_locked(&fiq->waitq); > kill = true; > @@ -500,6 +514,7 @@ static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req) > spin_unlock(&fiq->waitq.lock); > if (kill) > kill_fasync(&fiq->fasync, SIGIO, POLL_IN); > + return (int)kill; > } > > static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) > @@ -1959,8 +1974,9 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, > nbytes = -EINVAL; > else if (oh.error == -ENOSYS) > fc->no_interrupt = 1; > - else if (oh.error == -EAGAIN) > - queue_interrupt(&fc->iq, req); > + else if (oh.error == -EAGAIN && > + queue_interrupt(&fc->iq, req) < 0) > + nbytes = -EINVAL; > > fuse_put_request(fc, req); > fuse_copy_finish(cs); >