Received: by 2002:a25:e7d8:0:0:0:0:0 with SMTP id e207csp976346ybh; Wed, 11 Mar 2020 14:50:59 -0700 (PDT) X-Google-Smtp-Source: ADFU+vsA2zsf9QOXdAE14+twoQLHh8otFHr+cSjSb2jt3nLbYG4qbsc74ue+Ne6pGVR1SzFb1cFB X-Received: by 2002:a05:6808:b30:: with SMTP id t16mr522551oij.117.1583963459412; Wed, 11 Mar 2020 14:50:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1583963459; cv=none; d=google.com; s=arc-20160816; b=T69R9WjySJJLaeXQ5cS6Z27QF/8XUT4CP+np3OA6x/ufkgnycYkPhkCwtxv0QM41uu /lVIW4XaJkN9/VnaHh+4R8DWoBqMQX0BLBsWsO+hMuMVSmF0QjevTUDZDvENnzuXelaN Xv6pj2OV0j0GSMQM8DpZo219oME7ZzXtYevY40Ub+5dVHZIk51Y/uwnepEXLKUA4qltH nx4P3zkztHraipbT0x0+tGMJJxBRpakB+/Cjo0OZ6Fm4PAOtOrHf65+oN+pmAIUXu6eX z73Op8hzVhuHBsOyxXmR5rsGz87D1RMsJTFV8/HLHeRtjfstjTubxMv0cm1Elyj/tFz1 wjqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:message-id:references :in-reply-to:subject:cc:date:to:from; bh=TlI9hbwxGc4wP8sNZoiYvrXOsItZiFlMsXYW0TdCQpw=; b=EchDVEduTUS6F8l22OzAYpV1I5OxPzgffD+lEv4KRur6/+zEabRgSF5Jsi9U/m3NAX zxOvR1Q6iSt4gqWb65kvOKNbpPb1eO0ZB5HfIXiBRZ/Lj4AvAKO6Zd2KdAB0HHlMNMTf 7LttkEcUiLn9TsO9ko8E9jYEUP4E4jvYKhuS21dCf6thxqm24s8RG9YJh5vFMRi9gxp0 tB5rLF7xCA4HThA7eAFanxZTLCARM0mwmI6EMINJBLLxo1LD+qfkAfKAvgg09qkBIkoF 4k8nw9xq+vkpkWuW8zkX2nZdz/D/3tDHjC45MbG8fkBROtmvQv3pIIT5DEiJdoG1+Nu6 IWfg== ARC-Authentication-Results: i=1; mx.google.com; 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 v129si1536616oib.58.2020.03.11.14.50.47; Wed, 11 Mar 2020 14:50:59 -0700 (PDT) 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; 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 S1729687AbgCKVuV (ORCPT + 99 others); Wed, 11 Mar 2020 17:50:21 -0400 Received: from mx2.suse.de ([195.135.220.15]:49734 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729333AbgCKVuV (ORCPT ); Wed, 11 Mar 2020 17:50:21 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 4BCA7AAC7; Wed, 11 Mar 2020 21:50:19 +0000 (UTC) From: NeilBrown To: Jeff Layton , Stephen Rothwell Date: Thu, 12 Mar 2020 08:50:11 +1100 Cc: Linux Next Mailing List , Linux Kernel Mailing List Subject: [PATCH] locks: restore locks_delete_lock optimization In-Reply-To: <7d4c32b94a2ae900afa316c12047f7d79a31aaba.camel@kernel.org> References: <20200312011809.408fd045@canb.auug.org.au> <7d4c32b94a2ae900afa316c12047f7d79a31aaba.camel@kernel.org> Message-ID: <871rpyv9ws.fsf@notabene.neil.brown.name> MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable A recent patch (see Fixes: below) removed an optimization which is important as it avoids taking a lock in a common case. The comment justifying the optimisation was correct as far as it went, in that if the tests succeeded, then the values would remain stable and the test result will remain valid even without a lock. However after the test succeeds the lock can be freed while some other thread might have only just set ->blocker to NULL (thus allowing the test to succeed) but has not yet called wake_up() on the wq in the lock. If the wake_up happens after the lock is freed, a use-after-free error occu= rs. This patch restores the optimization and adds sufficient locking to avoid the use-after-free. Rather than using the global lock - which is too expensive - the waitq lock is used instead. We make use of wake_up_locked() which allows wake_up to be called while the lock is held. Now ->blocker is set to NULL and the wq is woken all while protected by the wq spinlock. Before the lock is freed, ->blockers is tested for NULL under the same spinlock. That test must now happen before =2D>blocker is set to NULL, or after it is safe to free the lock. Fixes: 6d390e4b5d48 ("locks: fix a potential use-after-free problem when wa= keup a waiter") Signed-off-by: NeilBrown =2D-- fs/locks.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/fs/locks.c b/fs/locks.c index 426b55d333d5..8aa04d5ac8b3 100644 =2D-- a/fs/locks.c +++ b/fs/locks.c @@ -735,11 +735,13 @@ static void __locks_wake_up_blocks(struct file_lock *= blocker) =20 waiter =3D list_first_entry(&blocker->fl_blocked_requests, struct file_lock, fl_blocked_member); + spin_lock(&waiter->fl_wait.lock); __locks_delete_block(waiter); if (waiter->fl_lmops && waiter->fl_lmops->lm_notify) waiter->fl_lmops->lm_notify(waiter); else =2D wake_up(&waiter->fl_wait); + wake_up_locked(&waiter->fl_wait); + spin_unlock(&waiter->fl_wait.lock); } } =20 @@ -753,6 +755,31 @@ int locks_delete_block(struct file_lock *waiter) { int status =3D -ENOENT; =20 + /* + * If fl_blocker is NULL, it won't be set again as this thread + * "owns" the lock and is the only one that might try to claim + * the lock. So it is safe to test fl_blocker locklessly. + * Also if fl_blocker is NULL, this waiter is not listed on + * fl_blocked_requests for some lock, so no other request can + * be added to the list of fl_blocked_requests for this + * request. So if fl_blocker is NULL, it is safe to + * locklessly check if fl_blocked_requests is empty. If both + * of these checks succeed, there is no need to take the lock. + * However, some other thread might have only *just* set + * fl_blocker to NULL and it about to send a wakeup on + * fl_wait, so we mustn't return too soon or we might free waiter + * before that wakeup can be sent. So take the fl_wait.lock + * to serialize with the wakeup in __locks_wake_up_blocks(). + */ + if (waiter->fl_blocker =3D=3D NULL) { + spin_lock(&waiter->fl_wait.lock); + if (waiter->fl_blocker =3D=3D NULL && + list_empty(&waiter->fl_blocked_requests)) { + spin_unlock(&waiter->fl_wait.lock); + return status; + } + spin_unlock(&waiter->fl_wait.lock); + } spin_lock(&blocked_lock_lock); if (waiter->fl_blocker) status =3D 0; =2D-=20 2.25.1 --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEG8Yp69OQ2HB7X0l6Oeye3VZigbkFAl5pXRQACgkQOeye3VZi gbm5exAAgfluIK5IiFv8YzhV1iAJOIuqgdu1lg+3FWPzk/5Vm/XFMY4qrao+5swJ z6mxj0lJRZbOdSID2tWvGpfByjq0PKNmcr55alLl4EePO3aO9m2fAsBqvPzvhT8V Bi+rjesDyknUqYWTxj0RKQau414C4IsrXgi3jcHwub2Acn+FJiHGfdJ4C3ZZL5r5 ZG6gXbnp0HHQ5zAVc4tqCYdj/2C4iNt4IwtWSRFhcNwgALynaUzV1lhaO6HmdIuJ ZAjn18Ye/AkBZmdgXUTYaL4IMQCqc4R0uJKLez+rMO/n8J+3qtNjacf4cAnKarFx nFZ110WqotCE+p1vEYgaA19TXboII3ruf87V4Y6QHCrjTvZ1UrMHJS3PNEZHSHia fe6UgvpN5/py/dFR8hIAVdAjlif0jI3MKAP+ZHa4hp2xUdYDKQa1t9kyOlZMbGsO +hzYkBeyFwfg8GxBtnlKMqGDUMQi2xxBbA+Y8x7TEqOpg+cM/Dm9iLP2CrYuFPcd jk+gkEmWFZ7dMqbTWQieXYaoQ6W0P+jk+9Xho0X/If8cRT4sKd/joGWvUEw0pLlT /e4JRhSCTFA4vLQnmWIe3NIRYMwwXHu+Sp8TJpgKPl7xvsCrxyO/9TYcBlYMfekq F10VwpFna3v0pTF/Kb4FVOfnbjjzvKvIvkBJTiEsq6i6KIyr6q8= =6N8S -----END PGP SIGNATURE----- --=-=-=--