Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp888413yba; Thu, 18 Apr 2019 11:14:46 -0700 (PDT) X-Google-Smtp-Source: APXvYqxGco2fQa8UwpyYZ+k5ommSJV4uHG9UHZN6s731SJtMTXx4qhcUl1Cj9XgG6eWk7wwAjun7 X-Received: by 2002:a62:6c6:: with SMTP id 189mr70280258pfg.36.1555611286909; Thu, 18 Apr 2019 11:14:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1555611286; cv=none; d=google.com; s=arc-20160816; b=ObFpIUeY0vUmt6LAn800V+XYmpt4Aymr2PdBQjFH+Wh8bO87l0hvN5+OKm8CNxnBAA cZODkJqmm6oEf+vlraPDNQXDVtAa4QxAnJAiXhZd3TTg7vpRpiFeQVfCuESTE2RDucJg ro3HMcrPvwQnFB6I8/96ndOynMC8p2IbMjwHupB/R+Y5MvjbqJc0JME22FYB4id9aKLd zjAAj5P7MQNz05XU4LHpKCnmPDPZf2/whe5o2X5MbWtdJkZo+3mhkR21Xe5+iM9luN04 nOA0oxfLmpsuRwt7RplY2+7wH6oA9pm6ymad/gZV636TjjVR5/LwxQbCD7rB/3DjZ9Aq 6VTg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=8OhfoWVfEZvgrd5/1I8uYrk1x+z+ryziBR60B19T66M=; b=K0hMuxWS1teEH0Jp05vkSlN4KEQ30pBWoDO4l6P7QWTb76ibUq9U8ebA/yj8GBIPGt 0R0vGhl7Ak6iTYqdBIqacUEFKQTImmo3oih9bq4kbua2V+l9qi6DP4mf6AqeuAwVyNV1 +AWNqFzx8eAUl0cM98axXsuVOmOLKS2CdesTfSdUI97F442bUG+Hn0GpG8DGElJYniKn vtqysMqLtPVZP9eQ2wBtp4Hd24o5jbrl2yhqevMBHG9Q3rkb9b5DHWh4jcz/VFk5Qheo h5jmUOaiMrAEgYdWNCokRLCpzUxtD+qabx1s5Wxr4YVmFRWL/1879HniRMRddmPqlZuH c80Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=EjB7lKc+; 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 m3si2737743pfh.249.2019.04.18.11.14.32; Thu, 18 Apr 2019 11:14:46 -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; dkim=pass header.i=@kernel.org header.s=default header.b=EjB7lKc+; 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 S2391527AbfDRSNA (ORCPT + 99 others); Thu, 18 Apr 2019 14:13:00 -0400 Received: from mail.kernel.org ([198.145.29.99]:45570 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2403906AbfDRSM5 (ORCPT ); Thu, 18 Apr 2019 14:12:57 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id AA09A21871; Thu, 18 Apr 2019 18:12:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1555611176; bh=+h4lgpY+l1qQr/JlzD4bm+Ct6ycPXUYCkERUSUk+iOc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EjB7lKc+VUUwlIA/AlXvpOLnX4OGorC2nCuuQGhvp4Fk7YvZPCGLEA9313+AvMgNF 1neEUKVwuFwxnGvUt1Swe4na0VFTVeeoaYuBlOKbkApJ8OgLqDOjaObU24pq4+i2y8 eDNZffvfxmRrH4qpscYvLRCmjvCJhzbtaflxAd9Y= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, David Howells , Marc Dionne , "David S. Miller" , Sasha Levin Subject: [PATCH 5.0 87/93] rxrpc: Fix client call connect/disconnect race Date: Thu, 18 Apr 2019 19:58:05 +0200 Message-Id: <20190418160445.618718697@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418160436.781762249@linuxfoundation.org> References: <20190418160436.781762249@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org [ Upstream commit 930c9f9125c85b5134b3e711bc252ecc094708e3 ] rxrpc_disconnect_client_call() reads the call's connection ID protocol value (call->cid) as part of that function's variable declarations. This is bad because it's not inside the locked section and so may race with someone granting use of the channel to the call. This manifests as an assertion failure (see below) where the call in the presumed channel (0 because call->cid wasn't set when we read it) doesn't match the call attached to the channel we were actually granted (if 1, 2 or 3). Fix this by moving the read and dependent calculations inside of the channel_lock section. Also, only set the channel number and pointer variables if cid is not zero (ie. unset). This problem can be induced by injecting an occasional error in rxrpc_wait_for_channel() before the call to schedule(). Make two further changes also: (1) Add a trace for wait failure in rxrpc_connect_call(). (2) Drop channel_lock before BUG'ing in the case of the assertion failure. The failure causes a trace akin to the following: rxrpc: Assertion failed - 18446612685268945920(0xffff8880beab8c00) == 18446612685268621312(0xffff8880bea69800) is false ------------[ cut here ]------------ kernel BUG at net/rxrpc/conn_client.c:824! ... RIP: 0010:rxrpc_disconnect_client_call+0x2bf/0x99d ... Call Trace: rxrpc_connect_call+0x902/0x9b3 ? wake_up_q+0x54/0x54 rxrpc_new_client_call+0x3a0/0x751 ? rxrpc_kernel_begin_call+0x141/0x1bc ? afs_alloc_call+0x1b5/0x1b5 rxrpc_kernel_begin_call+0x141/0x1bc afs_make_call+0x20c/0x525 ? afs_alloc_call+0x1b5/0x1b5 ? __lock_is_held+0x40/0x71 ? lockdep_init_map+0xaf/0x193 ? lockdep_init_map+0xaf/0x193 ? __lock_is_held+0x40/0x71 ? yfs_fs_fetch_data+0x33b/0x34a yfs_fs_fetch_data+0x33b/0x34a afs_fetch_data+0xdc/0x3b7 afs_read_dir+0x52d/0x97f afs_dir_iterate+0xa0/0x661 ? iterate_dir+0x63/0x141 iterate_dir+0xa2/0x141 ksys_getdents64+0x9f/0x11b ? filldir+0x111/0x111 ? do_syscall_64+0x3e/0x1a0 __x64_sys_getdents64+0x16/0x19 do_syscall_64+0x7d/0x1a0 entry_SYSCALL_64_after_hwframe+0x49/0xbe Fixes: 45025bceef17 ("rxrpc: Improve management and caching of client connection objects") Signed-off-by: David Howells Reviewed-by: Marc Dionne Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- include/trace/events/rxrpc.h | 2 ++ net/rxrpc/conn_client.c | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 5b50fe4906d2..7b60fd186cfe 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -76,6 +76,7 @@ enum rxrpc_client_trace { rxrpc_client_chan_disconnect, rxrpc_client_chan_pass, rxrpc_client_chan_unstarted, + rxrpc_client_chan_wait_failed, rxrpc_client_cleanup, rxrpc_client_count, rxrpc_client_discard, @@ -276,6 +277,7 @@ enum rxrpc_tx_point { EM(rxrpc_client_chan_disconnect, "ChDisc") \ EM(rxrpc_client_chan_pass, "ChPass") \ EM(rxrpc_client_chan_unstarted, "ChUnst") \ + EM(rxrpc_client_chan_wait_failed, "ChWtFl") \ EM(rxrpc_client_cleanup, "Clean ") \ EM(rxrpc_client_count, "Count ") \ EM(rxrpc_client_discard, "Discar") \ diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 5cf6d9f4761d..83797b3949e2 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -704,6 +704,7 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, ret = rxrpc_wait_for_channel(call, gfp); if (ret < 0) { + trace_rxrpc_client(call->conn, ret, rxrpc_client_chan_wait_failed); rxrpc_disconnect_client_call(call); goto out; } @@ -774,16 +775,22 @@ static void rxrpc_set_client_reap_timer(struct rxrpc_net *rxnet) */ void rxrpc_disconnect_client_call(struct rxrpc_call *call) { - unsigned int channel = call->cid & RXRPC_CHANNELMASK; struct rxrpc_connection *conn = call->conn; - struct rxrpc_channel *chan = &conn->channels[channel]; + struct rxrpc_channel *chan = NULL; struct rxrpc_net *rxnet = conn->params.local->rxnet; + unsigned int channel = -1; + u32 cid; + spin_lock(&conn->channel_lock); + + cid = call->cid; + if (cid) { + channel = cid & RXRPC_CHANNELMASK; + chan = &conn->channels[channel]; + } trace_rxrpc_client(conn, channel, rxrpc_client_chan_disconnect); call->conn = NULL; - spin_lock(&conn->channel_lock); - /* Calls that have never actually been assigned a channel can simply be * discarded. If the conn didn't get used either, it will follow * immediately unless someone else grabs it in the meantime. @@ -807,7 +814,10 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) goto out; } - ASSERTCMP(rcu_access_pointer(chan->call), ==, call); + if (rcu_access_pointer(chan->call) != call) { + spin_unlock(&conn->channel_lock); + BUG(); + } /* If a client call was exposed to the world, we save the result for * retransmission. -- 2.19.1