From patchwork Tue Jul 31 20:10:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 10551479 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E4E5313BB for ; Tue, 31 Jul 2018 21:26:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CBE302B336 for ; Tue, 31 Jul 2018 21:26:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BEF132B4CF; Tue, 31 Jul 2018 21:26:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 609092B336 for ; Tue, 31 Jul 2018 21:26:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731484AbeGaXI5 (ORCPT ); Tue, 31 Jul 2018 19:08:57 -0400 Received: from 1.mo2.mail-out.ovh.net ([46.105.63.121]:56073 "EHLO 1.mo2.mail-out.ovh.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725886AbeGaXI5 (ORCPT ); Tue, 31 Jul 2018 19:08:57 -0400 X-Greylist: delayed 2412 seconds by postgrey-1.27 at vger.kernel.org; Tue, 31 Jul 2018 19:08:57 EDT Received: from player794.ha.ovh.net (unknown [10.109.160.153]) by mo2.mail-out.ovh.net (Postfix) with ESMTP id E0551146BE8 for ; Tue, 31 Jul 2018 22:11:00 +0200 (CEST) Received: from awhome.eu (p579AA6EE.dip0.t-ipconnect.de [87.154.166.238]) (Authenticated sender: postmaster@awhome.eu) by player794.ha.ovh.net (Postfix) with ESMTPSA id 63DA11400A6; Tue, 31 Jul 2018 22:10:55 +0200 (CEST) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1533067848; bh=HB+iqFHcBBy3VLD5/ikuADzXYmGADU3+cw7v7Gh6uc8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=DW1VraAexc5ixb88mgi1rmwJ7NzRzKr3iuSwjIU89TGW5y2NpdGhFhWXhwNQ+HUER i+0IytKmJ+Jr/hbtFs1pkFATeNe8nZvISkhsl9VzPHNrhO9Q+TmzBOQqyvKyqkavNh XDGyvSrbZS03JfdaGR1BG5qJpGdueu0GE/tgvC00= To: johannes@sipsolutions.net Cc: linux-wireless@vger.kernel.org, greearb@candelatech.com, s.gottschall@dd-wrt.com, denkenz@gmail.com, Alexander Wetzel Subject: [PATCH v4 1/3] nl80211: Add ATOMIC_KEY_REPLACE API Date: Tue, 31 Jul 2018 22:10:28 +0200 Message-Id: <20180731201030.2619-2-alexander@wetzel-home.de> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180731201030.2619-1-alexander@wetzel-home.de> References: <20180731201030.2619-1-alexander@wetzel-home.de> X-Ovh-Tracer-Id: 14002817144476212337 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedtiedrledtgdduvdeiucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuqfggjfdpvefjgfevmfevgfenuceurghilhhouhhtmecufedttdenuc Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Drivers able to replace a in-use should set NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE to allow the userspace (e.g. hostapd or wpa_supplicant) to rekey the PTK without a full disassociation. The userspace must detect a PTK rekey attempt and only go ahead with the rekey if the driver has set this flag. When the driver is not supporting the feature the userspace has to perform a re-association. Ignoring this flag and continuing to rekey the connection can still work but has to be considered insecure and broken. It can leak cleartext packets or freeze the connection and is only supported to allow the userspace to be updated. Signed-off-by: Alexander Wetzel --- include/uapi/linux/nl80211.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 7acc16f34942..b41b9ade0449 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5224,6 +5224,11 @@ enum nl80211_feature_flags { * except for supported rates from the probe request content if requested * by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag. * + * @NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE: Driver/device confirm that they are + * able to rekey an in-use key correctly. Userspace must not rekey PTK keys + * if this flag is not set. Ignoring this can leak clear text packets and/or + * freeze the connection. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -5259,6 +5264,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_TXQS, NL80211_EXT_FEATURE_SCAN_RANDOM_SN, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT, + NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, From patchwork Tue Jul 31 20:10:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 10551377 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D691F13BF for ; Tue, 31 Jul 2018 20:50:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7035A2AF3D for ; Tue, 31 Jul 2018 20:50:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 635442B428; Tue, 31 Jul 2018 20:50:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C03032B441 for ; Tue, 31 Jul 2018 20:50:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729628AbeGaWcc (ORCPT ); Tue, 31 Jul 2018 18:32:32 -0400 Received: from 14.mo6.mail-out.ovh.net ([46.105.56.113]:46138 "EHLO 14.mo6.mail-out.ovh.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727006AbeGaWcc (ORCPT ); Tue, 31 Jul 2018 18:32:32 -0400 X-Greylist: delayed 1201 seconds by postgrey-1.27 at vger.kernel.org; Tue, 31 Jul 2018 18:32:31 EDT Received: from player799.ha.ovh.net (unknown [10.109.143.223]) by mo6.mail-out.ovh.net (Postfix) with ESMTP id A74B1170E50 for ; Tue, 31 Jul 2018 22:11:01 +0200 (CEST) Received: from awhome.eu (p579AA6EE.dip0.t-ipconnect.de [87.154.166.238]) (Authenticated sender: postmaster@awhome.eu) by player799.ha.ovh.net (Postfix) with ESMTPSA id 556B9520093; Tue, 31 Jul 2018 22:10:55 +0200 (CEST) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1533067848; bh=YkqaIyCcqDj4wsltUE0dxHpXpQaZNMeCqLaq1C0MJvE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=mZLj5Pykkltpl4AG64DsoF3X6GpPBcP7eECtLzYWQJ3lY/vVtY6J2AV6Kb4KtFtV2 5gTFPtX6MaCgNohiXH+yVdx1SUDnOu8dVM1oyUxTCv9P4CiGlsqn+5PmYtbkkwqLzp 3eYKYVcToxxWKNqOouMsahboTLZGNLdsBH1EyXrs= To: johannes@sipsolutions.net Cc: linux-wireless@vger.kernel.org, greearb@candelatech.com, s.gottschall@dd-wrt.com, denkenz@gmail.com, Alexander Wetzel Subject: [PATCH v4 2/3] mac80211: Define new driver callback replace_key Date: Tue, 31 Jul 2018 22:10:29 +0200 Message-Id: <20180731201030.2619-3-alexander@wetzel-home.de> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180731201030.2619-1-alexander@wetzel-home.de> References: <20180731201030.2619-1-alexander@wetzel-home.de> X-Ovh-Tracer-Id: 14003098619719523441 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedtiedrledtgdduvdeiucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuqfggjfdpvefjgfevmfevgfenuceurghilhhouhhtmecufedttdenuc Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Define the new driver callback replace_key in mac80211 for future use. Drivers able to replace a in-use key should implement this new callback to allow mac80211 drivers to securely use PTK rekeying. On return of the function drivers must guarantee they: - Did not send out any frames for the key unencrypted during the replace, - will not send out packets queued to them prior to the call encrypted with the new key - and will no longer hand over any which were encrypted with the old key to mac80211 when not handling IV/ICV in the driver. Packets handed over to the driver after the callback returned are expected to be send out encrypted with the new key and pending retransmissions must either be dropped or continue to use the old key. Mac80211 will not hand over outgoing packets for the key being replaced while the callback is running. Signed-off-by: Alexander Wetzel --- include/net/mac80211.h | 15 +++++++++++++++ net/mac80211/driver-ops.h | 20 ++++++++++++++++++++ net/mac80211/main.c | 5 +++++ net/mac80211/trace.h | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5790f55c241d..166a47f1886e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3137,6 +3137,17 @@ enum ieee80211_reconfig_type { * Returns a negative error code if the key can't be added. * The callback can sleep. * + * @replace_key: Replace an exiting in use key with a new one while guranteeing + * to not leak clear text packets. Implementing this callback will enable + * mac80211 to anounce NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE. + * Packets already queued must not be send out encrypted with the new key + * and packets decoded with the old key must not be handed over to mac80211 + * when the driver is not checking IV/ICV itself once the callback has been + * completed. + * Mac80211 will log an error when asked to use replace a PTK key + * without replace_key but will still perform the then potentially + * insecure action via set_key for backward combatibility for now. + * * @update_tkip_key: See the section "Hardware crypto acceleration" * This callback will be called in the context of Rx. Called for drivers * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. @@ -3585,6 +3596,10 @@ struct ieee80211_ops { int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); + int (*replace_key)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *old, + struct ieee80211_key_conf *new); void (*update_tkip_key)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_key_conf *conf, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 8f6998091d26..ebd7f1463336 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -255,6 +255,26 @@ static inline int drv_set_key(struct ieee80211_local *local, return ret; } +static inline int drv_replace_key(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *old_key, + struct ieee80211_key_conf *new_key) +{ + int ret; + + might_sleep(); + + sdata = get_bss_sdata(sdata); + if (!check_sdata_in_driver(sdata)) + return -EIO; + + trace_drv_replace_key(local, sdata, sta, old_key, new_key); + ret = local->ops->replace_key(&local->hw, &sdata->vif, sta, old_key, new_key); + trace_drv_return_int(local, ret); + return ret; +} + static inline void drv_update_tkip_key(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_key_conf *conf, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4fb2709cb527..84cc8005c19a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -572,9 +572,14 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT); } + if (ops->replace_key) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE); + if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + if (ops->wake_tx_queue) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 0ab69a1964f8..f93e00f1ae4d 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -603,6 +603,45 @@ TRACE_EVENT(drv_set_key, ) ); +TRACE_EVENT(drv_replace_key, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *old_key, + struct ieee80211_key_conf *new_key), + + TP_ARGS(local, sdata, sta, old_key, new_key), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + KEY_ENTRY + __field(u32, cipher2) + __field(u8, hw_key_idx2) + __field(u8, flags2) + __field(s8, keyidx2) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + KEY_ASSIGN(old_key); + __entry->cipher2 = new_key->cipher; + __entry->flags2 = new_key->flags; + __entry->keyidx2 = new_key->keyidx; + __entry->hw_key_idx2 = new_key->hw_key_idx; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT KEY_PR_FMT + " cipher2:0x%x, flags2=%#x, keyidx2=%d, hw_key_idx2=%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, KEY_PR_ARG, + __entry->cipher2, __entry->flags2, __entry->keyidx2, __entry->hw_key_idx2 + ) +); + TRACE_EVENT(drv_update_tkip_key, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, From patchwork Tue Jul 31 20:10:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 10551375 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C1F5613B8 for ; Tue, 31 Jul 2018 20:50:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B0C812AF33 for ; Tue, 31 Jul 2018 20:50:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A4E6B2AF8E; Tue, 31 Jul 2018 20:50:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 46FCA2AF33 for ; Tue, 31 Jul 2018 20:50:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731977AbeGaWcT (ORCPT ); Tue, 31 Jul 2018 18:32:19 -0400 Received: from 10.mo178.mail-out.ovh.net ([46.105.76.150]:51973 "EHLO 10.mo178.mail-out.ovh.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727072AbeGaWcT (ORCPT ); Tue, 31 Jul 2018 18:32:19 -0400 X-Greylist: delayed 1189 seconds by postgrey-1.27 at vger.kernel.org; Tue, 31 Jul 2018 18:32:16 EDT Received: from player735.ha.ovh.net (unknown [10.109.146.76]) by mo178.mail-out.ovh.net (Postfix) with ESMTP id 3750A1FF43 for ; Tue, 31 Jul 2018 22:11:00 +0200 (CEST) Received: from awhome.eu (p579AA6EE.dip0.t-ipconnect.de [87.154.166.238]) (Authenticated sender: postmaster@awhome.eu) by player735.ha.ovh.net (Postfix) with ESMTPSA id 6A47C1600A6; Tue, 31 Jul 2018 22:10:55 +0200 (CEST) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1533067848; bh=6oNnhKX66zA66LprQvLwSUNF8PumFxdN6F07dsJ3I3s=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=xzbzrjetu4Xa1ueWDrIWKWPs3874peY07s0B71WTVJgDZZz7orhmMn147cXQnCX3x UoCSg7QP8YbVvo26AqjiPgXbGaEAdXd/72+IKMTcbn9tr7Yktyrs7G6Tft8XtA9s0b 8iJzWxUvcQh0WzO/cx23Fr5kA1a5ThzvliybxC3s= To: johannes@sipsolutions.net Cc: linux-wireless@vger.kernel.org, greearb@candelatech.com, s.gottschall@dd-wrt.com, denkenz@gmail.com, Alexander Wetzel Subject: [PATCH v4 3/3] mac80211: Fix PTK rekey freezes and cleartext leaks Date: Tue, 31 Jul 2018 22:10:30 +0200 Message-Id: <20180731201030.2619-4-alexander@wetzel-home.de> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180731201030.2619-1-alexander@wetzel-home.de> References: <20180731201030.2619-1-alexander@wetzel-home.de> X-Ovh-Tracer-Id: 14002817141448907889 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedtiedrledtgdduvdeiucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuqfggjfdpvefjgfevmfevgfenuceurghilhhouhhtmecufedttdenuc Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Rekeying a pairwise key with encryption offload and only keyid 0 had multiple races. Two of them could freeze the wlan connection till rekeyed again and the third could send out packets in clear which should have been encrypted. 1) Freeze caused by incoming packets: If the local STA installed the key prior to the remote STA we still had the old key active in the hardware while mac80211 was already operating on the new key. The card could still hand over packets decoded with the old key to mac80211, bumping the new PN (IV) value to an incorrect high number and tricking the local replay detection to later drop all packets really sent with the new key. 2) Freeze caused by outgoing packets: If mac80211 was providing the PN (IV) and handed over a cleartext packets for encryption to the hardware prior to a key change the driver/card could have processed the queued packets after switching to the new key. This immediately bumped the PN (IV) value on the remote STA to an incorrect high number, which also froze the connection. 3) Clear text leak: Removing encryption offload from the card cleared the encryption offload flag only after the card had removed the key. Packets handed over between that were send out unencrypted. To prevent those issues we now stop queuing packets to the driver while replacing the key, replace the key first in the HW and stop/block new aggregation sessions during the rekey. This will only work correctly with drivers implementing replace_key and a userspace honoring NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE. If the driver is not implementing replace_key all three issues can still occur and the userspace must not rekey a running connection. With drivers implementing replace_key this fixes the (for rekeys) invalid unicast key install procedure from: - atomic switch over to the new key in mac80211 (TX still active!) - remove the old key in the HW (stops encryption offloading, switch to SW encryption and can leak clear text packets while doing that) - delete the inactive old key in mac80211 - add new key in the HW for encryption offloading (ending software encryption) to: - mark the old key as tainted to drop TX packets with the outgoing key - replace the key in HW with the new one using the new driver callback "replace_key" (driver still must guarantee it is not leaking cleartext itself) - atomic switch over to the new key in mac80211 (allow TX again) - delete the inactive old key in mac80211 For drivers not implementing the new callback "replace_key" it's unknown if the driver can replace the key without leaking cleartext packets. Mac80211 will therefore log an error message when trying to update the PTK key but still replace the key as instructed. Refusing cooperation is possible but considered to be the greater evil due to user visible changes. The mac80211 cleartext packet leak is still fixed, but potential cleartext packet leaks and the freezes - caused by the undefined driver behavior - can't be ruled out. The logic behind the updated rekey sequence: With the new sequence the HW will be unable to decode packets encrypted with the old key prior to switching to the new key in mac80211. Locking down TX during the rekey makes sure that there are no outgoing packets while the driver and card are switching to the new key. The driver is allowed to hand over packets decrypted with either the new or the old key till "replace_key" returns. But all packets queued prior to calling the callback must be either still be send out encrypted with the old key or be dropped. A RX aggregation session started prior to the rekey and completed after can still dump frames received with the old key at mac80211 after we switched over to the new key. This is avoided by stopping all RX and aggregation sessions when we replace a PTK key and are using key offloading. Signed-off-by: Alexander Wetzel --- net/mac80211/key.c | 123 ++++++++++++++++++++++++++++++++++++++------- net/mac80211/tx.c | 4 ++ 2 files changed, 110 insertions(+), 17 deletions(-) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index c054ac85793c..5a5f9e0d276e 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -248,6 +248,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) increment_tailroom_need_count(sdata); + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; ret = drv_set_key(key->local, DISABLE_KEY, sdata, sta ? &sta->sta : NULL, &key->conf); @@ -257,7 +258,63 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, sta ? sta->sta.addr : bcast_addr, ret); - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; +} + +static int ieee80211_hw_ptk_replace(struct ieee80211_key *old_key, + struct ieee80211_key *new_key, + bool canreplace) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local; + struct sta_info *sta; + int ret; + + if (!old_key || !new_key || !old_key->sta) + return -EINVAL; + + /* Running on software encryption */ + if (!(old_key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + return 0; + + assert_key_lock(old_key->local); + + sta = old_key->sta; + local = old_key->local; + sdata = old_key->sdata; + + /* Stop TX till we are on the new key */ + old_key->flags |= KEY_FLAG_TAINTED; + ieee80211_clear_fast_xmit(sta); + + if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION)) { + set_sta_flag(sta, WLAN_STA_BLOCK_BA); + ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_LOCAL_REQUEST); + } + + if (canreplace) { + ret = drv_replace_key(old_key->local, sdata, + &sta->sta, &old_key->conf, + &new_key->conf); + if (!ret) + new_key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + else + sdata_err(sdata, + "failed to replace key (%d) with key " \ + "(%d) for STA, %pM in hardware (%d)\n", + old_key->conf.keyidx, + new_key->conf.keyidx, + sta ? sta->sta.addr : bcast_addr, ret); + + old_key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + } else { + sdata_err(sdata, + "PTK rekey and old userspace software used. Some " + "packets to STA %pM may be send out without " + "encryption and the connection may also freeze!", + sta->sta.addr); + ret = 0; + } + return (ret); } static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, @@ -316,38 +373,74 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, } -static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, +static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, bool pairwise, struct ieee80211_key *old, struct ieee80211_key *new) { int idx; + int ret; bool defunikey, defmultikey, defmgmtkey; + bool canreplace = false; /* caller must provide at least one old/new */ if (WARN_ON(!new && !old)) - return; + return 0; + + /* Drivers can provide and signal support for replacing in-use + * keys by implementing the callback replace_key. If possible + * use that for PTK key replaces. If not we stick to an improved + * procedure with_set_key which may still leak clear text packets + * and freeze RX and/or TX for compatibility. + */ + if (new && new->local->ops->replace_key) + canreplace = true; if (new) list_add_tail_rcu(&new->list, &sdata->key_list); WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); - if (old) + if (old) { idx = old->conf.keyidx; - else + + if(new && sta && pairwise) { + ret = ieee80211_hw_ptk_replace(old, new, canreplace); + if (ret) + return ret; + } + } else { idx = new->conf.keyidx; + } + + if (new && !new->local->wowlan && + !(sta && old && canreplace)) { + /* Only safe to use for GTK keys! + * Doing this for an in use PTK key can trick our replay + * detection to kill RX and potentially also the TX of the + * remote station. But it's still allowed for PTKs when the + * driver is not implementing replace_key for backward + * combatibility for now. + */ + ret = ieee80211_key_enable_hw_accel(new); + if (ret) + return ret; + } if (sta) { if (pairwise) { rcu_assign_pointer(sta->ptk[idx], new); sta->ptk_idx = idx; - ieee80211_check_fast_xmit(sta); + if (new) { + clear_sta_flag(sta, WLAN_STA_BLOCK_BA); + ieee80211_check_fast_xmit(sta); + } } else { rcu_assign_pointer(sta->gtk[idx], new); } - ieee80211_check_fast_rx(sta); + if (new) + ieee80211_check_fast_rx(sta); } else { defunikey = old && old == key_mtx_dereference(sdata->local, @@ -380,6 +473,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, if (old) list_del_rcu(&old->list); + return 0; } struct ieee80211_key * @@ -654,7 +748,6 @@ int ieee80211_key_link(struct ieee80211_key *key, struct ieee80211_sub_if_data *sdata, struct sta_info *sta) { - struct ieee80211_local *local = sdata->local; struct ieee80211_key *old_key; int idx = key->conf.keyidx; bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; @@ -691,17 +784,13 @@ int ieee80211_key_link(struct ieee80211_key *key, increment_tailroom_need_count(sdata); - ieee80211_key_replace(sdata, sta, pairwise, old_key, key); - ieee80211_key_destroy(old_key, delay_tailroom); - - ieee80211_debugfs_key_add(key); + ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key); - if (!local->wowlan) { - ret = ieee80211_key_enable_hw_accel(key); - if (ret) - ieee80211_key_free(key, delay_tailroom); + if (!ret) { + ieee80211_debugfs_key_add(key); + ieee80211_key_destroy(old_key, true); } else { - ret = 0; + ieee80211_key_free(key, true); } out: diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cd332e3e1134..13228693324c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2951,6 +2951,10 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) if (!(build.key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) goto out; + /* Key is beeing removed */ + if (build.key->flags & KEY_FLAG_TAINTED) + goto out; + switch (build.key->conf.cipher) { case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: