[08/10] staging: wfx: allow to burn prevent rollback bit

Message ID 20200526171821.934581-9-Jerome.Pouiller@silabs.com
State New
Headers show
Series
  • [01/10] staging: wfx: drop unused variable
Related show

Commit Message

Jerome Pouiller May 26, 2020, 5:18 p.m.
From: Jérôme Pouiller <jerome.pouiller@silabs.com>

In case a security flaw is found in a version of firmware, the device
offers a way to disallow the loading an older firmware.

This patch provides a vendor extension to nl80211 to enable this
feature.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/staging/wfx/hif_api_general.h |  8 ++++++++
 drivers/staging/wfx/hif_tx.c          | 18 ++++++++++++++++++
 drivers/staging/wfx/hif_tx.h          |  1 +
 drivers/staging/wfx/nl80211_vendor.c  | 23 +++++++++++++++++++++++
 drivers/staging/wfx/nl80211_vendor.h  | 11 +++++++++++
 5 files changed, 61 insertions(+)

Patch

diff --git a/drivers/staging/wfx/hif_api_general.h b/drivers/staging/wfx/hif_api_general.h
index dba18a7ae9194..c8af3534700ca 100644
--- a/drivers/staging/wfx/hif_api_general.h
+++ b/drivers/staging/wfx/hif_api_general.h
@@ -361,4 +361,12 @@  struct hif_cnf_sl_configure {
 	__le32 status;
 } __packed;
 
+struct hif_req_prevent_rollback {
+	__le32 magic_word; // Return an error if not equal to 0x5C8912F3
+} __packed;
+
+struct hif_cnf_prevent_rollback {
+	__le32 status;
+} __packed;
+
 #endif
diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c
index 6db41587cc7a5..899e1eb71a44b 100644
--- a/drivers/staging/wfx/hif_tx.c
+++ b/drivers/staging/wfx/hif_tx.c
@@ -535,6 +535,24 @@  int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
 	return ret;
 }
 
+int hif_burn_prevent_rollback(struct wfx_dev *wdev, u32 magic_word)
+{
+	int ret;
+	struct hif_msg *hif;
+	struct hif_req_prevent_rollback *body = wfx_alloc_hif(sizeof(*body),
+							      &hif);
+
+	if (!hif)
+		return -ENOMEM;
+	body->magic_word = cpu_to_le32(magic_word);
+	wfx_fill_header(hif, -1, HIF_REQ_ID_PREVENT_ROLLBACK, sizeof(*body));
+	ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+	if (ret == le32_to_cpu(HIF_STATUS_ROLLBACK_SUCCESS))
+		ret = 0;
+	kfree(hif);
+	return ret;
+}
+
 int hif_sl_send_pub_keys(struct wfx_dev *wdev,
 			 const u8 *pubkey, const u8 *pubkey_hmac)
 {
diff --git a/drivers/staging/wfx/hif_tx.h b/drivers/staging/wfx/hif_tx.h
index e1da28aef706e..d29c72d94789a 100644
--- a/drivers/staging/wfx/hif_tx.h
+++ b/drivers/staging/wfx/hif_tx.h
@@ -57,6 +57,7 @@  int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
 int hif_beacon_transmit(struct wfx_vif *wvif, bool enable);
 int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id);
 int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len);
+int hif_burn_prevent_rollback(struct wfx_dev *wdev, u32 magic_word);
 int hif_sl_set_mac_key(struct wfx_dev *wdev,
 		       const u8 *slk_key, int destination);
 int hif_sl_config(struct wfx_dev *wdev, const unsigned long *bitmap);
diff --git a/drivers/staging/wfx/nl80211_vendor.c b/drivers/staging/wfx/nl80211_vendor.c
index ec2fd2d73885f..1a9d411718a73 100644
--- a/drivers/staging/wfx/nl80211_vendor.c
+++ b/drivers/staging/wfx/nl80211_vendor.c
@@ -7,6 +7,7 @@ 
 #include "nl80211_vendor.h"
 #include "wfx.h"
 #include "sta.h"
+#include "hif_tx.h"
 
 int wfx_nl_ps_timeout(struct wiphy *wiphy, struct wireless_dev *widev,
 		      const void *data, int data_len)
@@ -47,3 +48,25 @@  int wfx_nl_ps_timeout(struct wiphy *wiphy, struct wireless_dev *widev,
 	return rc;
 }
 
+int wfx_nl_burn_antirollback(struct wiphy *wiphy, struct wireless_dev *widev,
+			     const void *data, int data_len)
+{
+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+	struct wfx_dev *wdev = (struct wfx_dev *)hw->priv;
+	struct nlattr *tb[WFX_NL80211_ATTR_MAX];
+	u32 magic;
+	int rc;
+
+	rc = nla_parse(tb, WFX_NL80211_ATTR_MAX - 1, data, data_len,
+		       wfx_nl_policy, NULL);
+	if (rc)
+		return rc;
+	if (!tb[WFX_NL80211_ATTR_ROLLBACK_MAGIC])
+		return -EINVAL;
+	magic = nla_get_u32(tb[WFX_NL80211_ATTR_ROLLBACK_MAGIC]);
+	rc = hif_burn_prevent_rollback(wdev, magic);
+	if (rc)
+		return -EINVAL;
+	return 0;
+}
+
diff --git a/drivers/staging/wfx/nl80211_vendor.h b/drivers/staging/wfx/nl80211_vendor.h
index c069330e240a9..49efe8716a654 100644
--- a/drivers/staging/wfx/nl80211_vendor.h
+++ b/drivers/staging/wfx/nl80211_vendor.h
@@ -16,18 +16,23 @@ 
 
 int wfx_nl_ps_timeout(struct wiphy *wiphy, struct wireless_dev *widev,
 		      const void *data, int data_len);
+int wfx_nl_burn_antirollback(struct wiphy *wiphy, struct wireless_dev *widev,
+			     const void *data, int data_len);
 
 enum {
 	WFX_NL80211_SUBCMD_PS_TIMEOUT                   = 0x10,
+	WFX_NL80211_SUBCMD_BURN_PREVENT_ROLLBACK        = 0x20,
 };
 
 enum {
 	WFX_NL80211_ATTR_PS_TIMEOUT     = 1,
+	WFX_NL80211_ATTR_ROLLBACK_MAGIC = 2,
 	WFX_NL80211_ATTR_MAX
 };
 
 static const struct nla_policy wfx_nl_policy[WFX_NL80211_ATTR_MAX] = {
 	[WFX_NL80211_ATTR_PS_TIMEOUT]     = NLA_POLICY_RANGE(NLA_S32, -1, 127),
+	[WFX_NL80211_ATTR_ROLLBACK_MAGIC] = { .type = NLA_U32 },
 };
 
 static const struct wiphy_vendor_command wfx_nl80211_vendor_commands[] = {
@@ -38,6 +43,12 @@  static const struct wiphy_vendor_command wfx_nl80211_vendor_commands[] = {
 		.policy = wfx_nl_policy,
 		.doit = wfx_nl_ps_timeout,
 		.maxattr = WFX_NL80211_ATTR_MAX - 1,
+	}, {
+		.info.vendor_id = WFX_NL80211_ID,
+		.info.subcmd = WFX_NL80211_SUBCMD_BURN_PREVENT_ROLLBACK,
+		.policy = wfx_nl_policy,
+		.doit = wfx_nl_burn_antirollback,
+		.maxattr = WFX_NL80211_ATTR_MAX - 1,
 	},
 };