Received: by 2002:ac0:e350:0:0:0:0:0 with SMTP id g16csp1941448imn; Mon, 1 Aug 2022 05:51:33 -0700 (PDT) X-Google-Smtp-Source: AGRyM1t9Na0mLGzGdOybSe43/sJr+iUEAEXhBr0hChyd229KLj8EzmioGx8fbkWpZ/oM+0dlTRGO X-Received: by 2002:a17:907:7631:b0:72b:3a31:6cb8 with SMTP id jy17-20020a170907763100b0072b3a316cb8mr12207263ejc.372.1659358292835; Mon, 01 Aug 2022 05:51:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1659358292; cv=none; d=google.com; s=arc-20160816; b=lmwRQ778RxJwXz3HCK4f08rL7cNDy8hoHU59pNksSdP8o8AHGWst2tkrXMUFDQpVWz cvavza9PL6wXZwr2LQgsiDcY07WXUApD3EjtbsXesh3IA+05yJ4ljruY87zfPMWStFUL 8wZvGTIqPLykG8I03e4OaRRNInXS6rdQvwroV1TVtpcXaiU4fucC4CHA5HgVyVsTBO4O 4Won/PSGEzKpkNUHOzUKeC6uIbrCAvGdj//ECTPeK9B9LpF+z1ci1MLK3B8RZiJmZwC+ 1/H+P6rmMHvi1BuS9wXHIA2NZE7wl5wKoymToWnvH3K4kD3zrahEOeFTyHbohhgDNqd6 7I2w== 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 :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=kaMj+dfCYlnAnLDY7sn0E2PQKjlrQ+w16Z7h3TM+GLQ=; b=h/smQJB0WRwOUGevHeCWpxz+Gf7tI7I8Da4ib6lY6m93izMzMF6LzQKs+cPcTsRtnu eqrTYm3MNXEots7quuULuojjILMe9B/l6dFdMTGYNH4KKaSJPRx1uZdw4ogM1rpCPMao 9SbDE6U808CR7LOfuGIC00ydTDEM4mYhGcksH8oT/Lm0vuRTfYn8K6RQ8BoIfJtZ3Jn1 XLG1hNsfsuApbnBOQmNxVMP9QPJjwQ4d8mlV/Kl6DwPqaEz6NDAk+agCab5MgeUJa3Er 1oFEUI29ExV2P3SF5Xyre6nvEyNuq/EJRh11YxkpOQpx26aafwIY8WRCRUllKy5HveDv 3JFQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="dxRzUA/b"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id dm16-20020a170907949000b00730928e31cbsi1652817ejc.882.2022.08.01.05.51.07; Mon, 01 Aug 2022 05:51:32 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="dxRzUA/b"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233976AbiHAMKU (ORCPT + 99 others); Mon, 1 Aug 2022 08:10:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56230 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233631AbiHAMJh (ORCPT ); Mon, 1 Aug 2022 08:09:37 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5036F6610D; Mon, 1 Aug 2022 04:56:21 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id BCE4CB81171; Mon, 1 Aug 2022 11:56:19 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2A5F2C433D6; Mon, 1 Aug 2022 11:56:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1659354978; bh=5hFJJ5gAtqb4rt193r1r4mkbDulYR0rJCVrXO3f4blY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dxRzUA/bXlIhHaw2cvz3oPTAPI/LYrdtybBh6rxFwbE6tL+/yvqngOWmBV7qZPCEu b2i2EXV4jNVmJHf54q2PiWD4jYtmGS9zOfq1QD8k6Z6OwB23NQXw6WiUSD45dzhjPv VY3PxljB4CChHMXBxkiyhgU27HXBhfr/U5lgaPjs= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, syzbot+03d7b43290037d1f87ca@syzkaller.appspotmail.com, David Howells , keyrings@vger.kernel.org, Linus Torvalds Subject: [PATCH 5.18 19/88] watch_queue: Fix missing locking in add_watch_to_object() Date: Mon, 1 Aug 2022 13:46:33 +0200 Message-Id: <20220801114138.914986548@linuxfoundation.org> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220801114138.041018499@linuxfoundation.org> References: <20220801114138.041018499@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Linus Torvalds commit e64ab2dbd882933b65cd82ff6235d705ad65dbb6 upstream. If a watch is being added to a queue, it needs to guard against interference from addition of a new watch, manual removal of a watch and removal of a watch due to some other queue being destroyed. KEYCTL_WATCH_KEY guards against this for the same {key,queue} pair by holding the key->sem writelocked and by holding refs on both the key and the queue - but that doesn't prevent interaction from other {key,queue} pairs. While add_watch_to_object() does take the spinlock on the event queue, it doesn't take the lock on the source's watch list. The assumption was that the caller would prevent that (say by taking key->sem) - but that doesn't prevent interference from the destruction of another queue. Fix this by locking the watcher list in add_watch_to_object(). Fixes: c73be61cede5 ("pipe: Add general notification queue support") Reported-by: syzbot+03d7b43290037d1f87ca@syzkaller.appspotmail.com Signed-off-by: David Howells cc: keyrings@vger.kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/watch_queue.c | 58 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 22 deletions(-) --- a/kernel/watch_queue.c +++ b/kernel/watch_queue.c @@ -454,6 +454,33 @@ void init_watch(struct watch *watch, str rcu_assign_pointer(watch->queue, wqueue); } +static int add_one_watch(struct watch *watch, struct watch_list *wlist, struct watch_queue *wqueue) +{ + const struct cred *cred; + struct watch *w; + + hlist_for_each_entry(w, &wlist->watchers, list_node) { + struct watch_queue *wq = rcu_access_pointer(w->queue); + if (wqueue == wq && watch->id == w->id) + return -EBUSY; + } + + cred = current_cred(); + if (atomic_inc_return(&cred->user->nr_watches) > task_rlimit(current, RLIMIT_NOFILE)) { + atomic_dec(&cred->user->nr_watches); + return -EAGAIN; + } + + watch->cred = get_cred(cred); + rcu_assign_pointer(watch->watch_list, wlist); + + kref_get(&wqueue->usage); + kref_get(&watch->usage); + hlist_add_head(&watch->queue_node, &wqueue->watches); + hlist_add_head_rcu(&watch->list_node, &wlist->watchers); + return 0; +} + /** * add_watch_to_object - Add a watch on an object to a watch list * @watch: The watch to add @@ -468,34 +495,21 @@ void init_watch(struct watch *watch, str */ int add_watch_to_object(struct watch *watch, struct watch_list *wlist) { - struct watch_queue *wqueue = rcu_access_pointer(watch->queue); - struct watch *w; + struct watch_queue *wqueue; + int ret = -ENOENT; - hlist_for_each_entry(w, &wlist->watchers, list_node) { - struct watch_queue *wq = rcu_access_pointer(w->queue); - if (wqueue == wq && watch->id == w->id) - return -EBUSY; - } - - watch->cred = get_current_cred(); - rcu_assign_pointer(watch->watch_list, wlist); - - if (atomic_inc_return(&watch->cred->user->nr_watches) > - task_rlimit(current, RLIMIT_NOFILE)) { - atomic_dec(&watch->cred->user->nr_watches); - put_cred(watch->cred); - return -EAGAIN; - } + rcu_read_lock(); + wqueue = rcu_access_pointer(watch->queue); if (lock_wqueue(wqueue)) { - kref_get(&wqueue->usage); - kref_get(&watch->usage); - hlist_add_head(&watch->queue_node, &wqueue->watches); + spin_lock(&wlist->lock); + ret = add_one_watch(watch, wlist, wqueue); + spin_unlock(&wlist->lock); unlock_wqueue(wqueue); } - hlist_add_head_rcu(&watch->list_node, &wlist->watchers); - return 0; + rcu_read_unlock(); + return ret; } EXPORT_SYMBOL(add_watch_to_object);