Commit 12d60c1e authored by Johannes Berg's avatar Johannes Berg Committed by Luca Coelho

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: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20211017123741.d1514964e6a7.I18f8c2ce8082952af7cfe5f8fe75fe51851b8853@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent fad92a1d
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment