aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2021-10-17 12:40:13 +0300
committerLuca Coelho <luciano.coelho@intel.com>2021-10-22 10:49:00 +0300
commit12d60c1efc29e19f4dc0dc70cd48ce097fce6447 (patch)
tree76ea9ea491dd1b8077da0044bfcf6c7e5f881c23 /drivers/net/wireless/intel/iwlwifi/mvm/ops.c
parentiwlwifi: parse debug exclude data from firmware file (diff)
downloadlinux-dev-12d60c1efc29e19f4dc0dc70cd48ce097fce6447.tar.xz
linux-dev-12d60c1efc29e19f4dc0dc70cd48ce097fce6447.zip
iwlwifi: mvm: scrub key material in firmware dumps
Use the previously added infrastructure to scrub key material in firmware dumps: * in the TX FIFO data, just search for each key that we know about and override such data * scrub various commands that we sent to the firmware if they're present * in firmware memory, where advertised by firmware TLVs Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Link: https://lore.kernel.org/r/iwlwifi.20211017123741.d1514964e6a7.I18f8c2ce8082952af7cfe5f8fe75fe51851b8853@changeid Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c179
1 files changed, 178 insertions, 1 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index b7f203fe7753..3b0d5a068541 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -725,6 +725,183 @@ static int iwl_mvm_start_post_nvm(struct iwl_mvm *mvm)
return 0;
}
+struct iwl_mvm_frob_txf_data {
+ u8 *buf;
+ size_t buflen;
+};
+
+static void iwl_mvm_frob_txf_key_iter(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ void *data)
+{
+ struct iwl_mvm_frob_txf_data *txf = data;
+ u8 keylen, match, matchend;
+ u8 *keydata;
+ size_t i;
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ keydata = key->key;
+ keylen = key->keylen;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ /*
+ * WEP has short keys which might show up in the payload,
+ * and then you can deduce the key, so in this case just
+ * remove all FIFO data.
+ * For TKIP, we don't know the phase 2 keys here, so same.
+ */
+ memset(txf->buf, 0xBB, txf->buflen);
+ return;
+ default:
+ return;
+ }
+
+ /* scan for key material and clear it out */
+ match = 0;
+ for (i = 0; i < txf->buflen; i++) {
+ if (txf->buf[i] != keydata[match]) {
+ match = 0;
+ continue;
+ }
+ match++;
+ if (match == keylen) {
+ memset(txf->buf + i - keylen, 0xAA, keylen);
+ match = 0;
+ }
+ }
+
+ /* we're dealing with a FIFO, so check wrapped around data */
+ matchend = match;
+ for (i = 0; match && i < keylen - match; i++) {
+ if (txf->buf[i] != keydata[match])
+ break;
+ match++;
+ if (match == keylen) {
+ memset(txf->buf, 0xAA, i + 1);
+ memset(txf->buf + txf->buflen - matchend, 0xAA,
+ matchend);
+ break;
+ }
+ }
+}
+
+static void iwl_mvm_frob_txf(void *ctx, void *buf, size_t buflen)
+{
+ struct iwl_mvm_frob_txf_data txf = {
+ .buf = buf,
+ .buflen = buflen,
+ };
+ struct iwl_mvm *mvm = ctx;
+
+ /* embedded key material exists only on old API */
+ if (iwl_mvm_has_new_tx_api(mvm))
+ return;
+
+ rcu_read_lock();
+ ieee80211_iter_keys_rcu(mvm->hw, NULL, iwl_mvm_frob_txf_key_iter, &txf);
+ rcu_read_unlock();
+}
+
+static void iwl_mvm_frob_hcmd(void *ctx, void *hcmd, size_t len)
+{
+ /* we only use wide headers for commands */
+ struct iwl_cmd_header_wide *hdr = hcmd;
+ unsigned int frob_start = sizeof(*hdr), frob_end = 0;
+
+ if (len < sizeof(hdr))
+ return;
+
+ /* all the commands we care about are in LONG_GROUP */
+ if (hdr->group_id != LONG_GROUP)
+ return;
+
+ switch (hdr->cmd) {
+ case WEP_KEY:
+ case WOWLAN_TKIP_PARAM:
+ case WOWLAN_KEK_KCK_MATERIAL:
+ case ADD_STA_KEY:
+ /*
+ * blank out everything here, easier than dealing
+ * with the various versions of the command
+ */
+ frob_end = INT_MAX;
+ break;
+ case MGMT_MCAST_KEY:
+ frob_start = offsetof(struct iwl_mvm_mgmt_mcast_key_cmd, igtk);
+ BUILD_BUG_ON(offsetof(struct iwl_mvm_mgmt_mcast_key_cmd, igtk) !=
+ offsetof(struct iwl_mvm_mgmt_mcast_key_cmd_v1, igtk));
+
+ frob_end = offsetofend(struct iwl_mvm_mgmt_mcast_key_cmd, igtk);
+ BUILD_BUG_ON(offsetof(struct iwl_mvm_mgmt_mcast_key_cmd, igtk) <
+ offsetof(struct iwl_mvm_mgmt_mcast_key_cmd_v1, igtk));
+ break;
+ }
+
+ if (frob_start >= frob_end)
+ return;
+
+ if (frob_end > len)
+ frob_end = len;
+
+ memset((u8 *)hcmd + frob_start, 0xAA, frob_end - frob_start);
+}
+
+static void iwl_mvm_frob_mem(void *ctx, u32 mem_addr, void *mem, size_t buflen)
+{
+ const struct iwl_dump_exclude *excl;
+ struct iwl_mvm *mvm = ctx;
+ int i;
+
+ switch (mvm->fwrt.cur_fw_img) {
+ case IWL_UCODE_INIT:
+ default:
+ /* not relevant */
+ return;
+ case IWL_UCODE_REGULAR:
+ case IWL_UCODE_REGULAR_USNIFFER:
+ excl = mvm->fw->dump_excl;
+ break;
+ case IWL_UCODE_WOWLAN:
+ excl = mvm->fw->dump_excl_wowlan;
+ break;
+ }
+
+ BUILD_BUG_ON(sizeof(mvm->fw->dump_excl) !=
+ sizeof(mvm->fw->dump_excl_wowlan));
+
+ for (i = 0; i < ARRAY_SIZE(mvm->fw->dump_excl); i++) {
+ u32 start, end;
+
+ if (!excl[i].addr || !excl[i].size)
+ continue;
+
+ start = excl[i].addr;
+ end = start + excl[i].size;
+
+ if (end <= mem_addr || start >= mem_addr + buflen)
+ continue;
+
+ if (start < mem_addr)
+ start = mem_addr;
+
+ if (end > mem_addr + buflen)
+ end = mem_addr + buflen;
+
+ memset((u8 *)mem + start - mem_addr, 0xAA, end - start);
+ }
+}
+
+static const struct iwl_dump_sanitize_ops iwl_mvm_sanitize_ops = {
+ .frob_txf = iwl_mvm_frob_txf,
+ .frob_hcmd = iwl_mvm_frob_hcmd,
+ .frob_mem = iwl_mvm_frob_mem,
+};
+
static struct iwl_op_mode *
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@@ -774,7 +951,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->hw = hw;
iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm,
- NULL, NULL, dbgfs_dir);
+ &iwl_mvm_sanitize_ops, mvm, dbgfs_dir);
iwl_mvm_get_acpi_tables(mvm);