Received: by 10.213.65.68 with SMTP id h4csp1757719imn; Mon, 19 Mar 2018 12:26:11 -0700 (PDT) X-Google-Smtp-Source: AG47ELt9g7+2uufmu66r5HGQrsn61r5lopqbxb1ycfDxOipyQgRKaOunLr53C0KO2R6hvy9w/CoA X-Received: by 2002:a17:902:526:: with SMTP id 35-v6mr13988200plf.276.1521487571605; Mon, 19 Mar 2018 12:26:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521487571; cv=none; d=google.com; s=arc-20160816; b=E4KWrdbVeBUIXAa4a0r+yS9sbtfBztk1eAB49Pn8xjyqfpnzxffXKJRTg1cVYl1IaW aw65v0wAk5QO4VBRBq/LGHnaAV/9CIj1a/+0Xzl8232ggIRh119VHDxf/Ja6hzdT+a2k 2gyK+t1eKT6vlIauTwkOGu29ZxA6n5A6y/1AXnwpxXLuZMIVOLvMqdydEMs//4dn6zka fiiJ20bo5kn1GD8QH0j0VRNXkEpOJVL9qSF2quqieF4983aNwcb7BehDVOgeBlPWkx99 gGoWyqbi/U0d7Nwhq18Q+NkIMvR3U4vxrZM+ycWXf2InVqnfHJWE1Ig703xKZ7fhw0du PIWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=zLMGdmJjjffiniJQ4ndbhQwX8bB/9dhlEzZaaJEJS6s=; b=k5O3n5RMvpva5qLSC+f4kBGVE1UPgR33FX2GwEsCmr76rMMjFv4VsPDc60Jbu12DlP zyqT2jTMTTNMaBlE4Kj8ovOTKVa2Vjz5lukEEiC0kkljRWQCKkHyyui0uYh/Zgj95mjt 2KcgUs1L4mxjpPqKSwMjadZePAfue0cJWaACfPttZcVTHXJyTjU9iK22LT7vHHHhRVNz ITAekGUJzLCWm7u9m8fG3s2gPrrdaJYVQHU3wSzFl/CDDk1hQQ14PTO3NdbbV/xxE83O MzaC67eG+hN+zUAxlu2VqnH1djq/BpjhRPgta+MWFoiU2dPr+lhlivSSMmHBamtLrTep UFnA== 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 e127si422509pfc.315.2018.03.19.12.25.57; Mon, 19 Mar 2018 12:26:11 -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 S966419AbeCSTXN (ORCPT + 99 others); Mon, 19 Mar 2018 15:23:13 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:50142 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1031549AbeCSSYw (ORCPT ); Mon, 19 Mar 2018 14:24:52 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id D73BFFD2; Mon, 19 Mar 2018 18:24:51 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dean Jenkins , Marcel Holtmann , Sasha Levin Subject: [PATCH 4.9 156/241] Bluetooth: Avoid bt_accept_unlink() double unlinking Date: Mon, 19 Mar 2018 19:07:01 +0100 Message-Id: <20180319180757.629475999@linuxfoundation.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180319180751.172155436@linuxfoundation.org> References: <20180319180751.172155436@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 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 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Dean Jenkins [ Upstream commit 27bfbc21a0c0f711fa5382de026c7c0700c9ea28 ] There is a race condition between a thread calling bt_accept_dequeue() and a different thread calling bt_accept_unlink(). Protection against concurrency is implemented using sk locking. However, sk locking causes serialisation of the bt_accept_dequeue() and bt_accept_unlink() threads. This serialisation can cause bt_accept_dequeue() to obtain the sk from the parent list but becomes blocked waiting for the sk lock held by the bt_accept_unlink() thread. bt_accept_unlink() unlinks sk and this thread releases the sk lock unblocking bt_accept_dequeue() which potentially runs bt_accept_unlink() again on the same sk causing a crash. The attempt to double unlink the same sk from the parent list can cause a NULL pointer dereference crash due to bt_sk(sk)->parent becoming NULL on the first unlink, followed by the second unlink trying to execute bt_sk(sk)->parent->sk_ack_backlog-- in bt_accept_unlink() which crashes. When sk is in the parent list, bt_sk(sk)->parent will be not be NULL. When sk is removed from the parent list, bt_sk(sk)->parent is set to NULL. Therefore, add a defensive check for bt_sk(sk)->parent not being NULL to ensure that sk is still in the parent list after the sk lock has been taken in bt_accept_dequeue(). If bt_sk(sk)->parent is detected as being NULL then restart the loop so that the loop variables are refreshed to use the latest values. This is necessary as list_for_each_entry_safe() is not thread safe so causing a risk of an infinite loop occurring as sk could point to itself. In addition, in bt_accept_dequeue() increase the sk reference count to protect against early freeing of sk. Early freeing can be possible if the bt_accept_unlink() thread calls l2cap_sock_kill() or rfcomm_sock_kill() functions before bt_accept_dequeue() gets the sk lock. For test purposes, the probability of failure can be increased by putting a msleep of 1 second in bt_accept_dequeue() between getting the sk and waiting for the sk lock. This exposes the fact that the loop list_for_each_entry_safe(p, n, &bt_sk(parent)->accept_q) is not safe from threads that unlink sk from the list in parallel with the loop which can cause sk to become stale within the loop. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/af_bluetooth.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -163,6 +163,9 @@ void bt_accept_enqueue(struct sock *pare } EXPORT_SYMBOL(bt_accept_enqueue); +/* Calling function must hold the sk lock. + * bt_sk(sk)->parent must be non-NULL meaning sk is in the parent list. + */ void bt_accept_unlink(struct sock *sk) { BT_DBG("sk %p state %d", sk, sk->sk_state); @@ -181,11 +184,32 @@ struct sock *bt_accept_dequeue(struct so BT_DBG("parent %p", parent); +restart: list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) { sk = (struct sock *)s; + /* Prevent early freeing of sk due to unlink and sock_kill */ + sock_hold(sk); lock_sock(sk); + /* Check sk has not already been unlinked via + * bt_accept_unlink() due to serialisation caused by sk locking + */ + if (!bt_sk(sk)->parent) { + BT_DBG("sk %p, already unlinked", sk); + release_sock(sk); + sock_put(sk); + + /* Restart the loop as sk is no longer in the list + * and also avoid a potential infinite loop because + * list_for_each_entry_safe() is not thread safe. + */ + goto restart; + } + + /* sk is safely in the parent list so reduce reference count */ + sock_put(sk); + /* FIXME: Is this check still needed */ if (sk->sk_state == BT_CLOSED) { bt_accept_unlink(sk);