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>
This commit is contained in:
parent
fad92a1d11
commit
12d60c1efc
@ -725,6 +725,183 @@ static int iwl_mvm_start_post_nvm(struct iwl_mvm *mvm)
|
|||||||
return 0;
|
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 *
|
static struct iwl_op_mode *
|
||||||
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||||
const struct iwl_fw *fw, struct dentry *dbgfs_dir)
|
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;
|
mvm->hw = hw;
|
||||||
|
|
||||||
iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm,
|
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);
|
iwl_mvm_get_acpi_tables(mvm);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user