wifi: iwlwifi: dvm: Add struct_group for struct iwl_keyinfo keys
Subsystems (3)
PATCH 1/1 wifi: iwlwifi: dvm: Add struct_group for struct iwl_keyinfo keys
Function iwlagn_send_sta_key() was trying to write across multiple structure members in a single memcpy(). Add a struct group "keys" to let the compiler see the intended bounds of the memcpy, which includes the tkip keys as well. Silences false positive memcpy() run-time warning:
memcpy: detected field-spanning write (size 32) of single field "sta_cmd.key.key" at drivers/net/wireless/intel/iwlwifi/dvm/sta.c:1103 (size 16)
--- drivers/net/wireless/intel/iwlwifi/dvm/commands.h | 10 ++++++---- drivers/net/wireless/intel/iwlwifi/dvm/sta.c | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-)
drivers/net/wireless/intel/iwlwifi/dvm/commands.h +6 -4
@@ -783,10 +783,12 @@ struct iwl_keyinfo {__le16 tkip_rx_ttak[5 ];/* 10-byte unicast TKIP TTAK */ u8 key_offset;u8 reserved2; -u8 key[16 ];/* 16-byte unicast decryption key */ -__le64 tx_secur_seq_cnt; -__le64 hw_tkip_mic_rx_key; -__le64 hw_tkip_mic_tx_key; +struct_group (keys, + u8 key[16]; /* 16-byte unicast decryption key */ +__le64 tx_secur_seq_cnt; +__le64 hw_tkip_mic_rx_key; +__le64 hw_tkip_mic_tx_key; + ); } __packed;/**
drivers/net/wireless/intel/iwlwifi/dvm/sta.c +2 -2
@@ -1093,14 +1093,14 @@ static int iwlagn_send_sta_key(struct iwl_priv *priv,switch (keyconf->cipher) {case WLAN_CIPHER_SUITE_CCMP : key_flags |=STA_KEY_FLG_CCMP ; -memcpy (sta_cmd.key.key, keyconf->key, keyconf->keylen); +memcpy (&sta_cmd.key.keys, keyconf->key, keyconf->keylen);break ;case WLAN_CIPHER_SUITE_TKIP : key_flags |=STA_KEY_FLG_TKIP ; sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;for (i =0 ; i <5 ; i++) sta_cmd.key.tkip_rx_ttak[i] =cpu_to_le16 (tkip_p1k[i]); -memcpy (sta_cmd.key.key, keyconf->key, keyconf->keylen); +memcpy (&sta_cmd.key.keys, keyconf->key, keyconf->keylen);break ;case WLAN_CIPHER_SUITE_WEP104 : key_flags |=STA_KEY_FLG_KEY_SIZE_MSK ;
Signature · 1 line
2.34.1
Quoted 8 lines · Kees Cook
Function
iwlagn_send_sta_key()was trying to write across multiple structure members in a singlememcpy(). Add a struct group "keys" to let the compiler see the intended bounds of the memcpy, which includes the tkip keys as well. Silences false positivememcpy()run-time warning:memcpy: detected field-spanning write (size 32) of single field "sta_cmd.key.key" at
drivers/net/wireless/intel/iwlwifi/dvm/sta.c:1103(size 16)
Quoted 13 lines
Cc Gregory Greenman <[email protected]>Cc Kalle Valo <[email protected]>Cc "David S. Miller" <[email protected]>Cc Eric Dumazet <[email protected]>Cc Jakub Kicinski <[email protected]>Cc Paolo Abeni <[email protected]>Cc Johannes Berg <[email protected]>Cc Benjamin Berg <[email protected]>Cc Sriram R <[email protected]>Signed-off-by Kees Cook <[email protected]>
drivers/net/wireless/intel/iwlwifi/dvm/sta.c static int iwlagn_send_sta_key(struct iwl_priv *priv, · line 1096
Quoted 5 lines · Kees Cook
drivers/net/wireless/intel/iwlwifi/dvm/sta.c +1
-1case WLAN_CIPHER_SUITE_CCMP : key_flags |=STA_KEY_FLG_CCMP ; -memcpy (sta_cmd.key.key, keyconf->key, keyconf->keylen); +memcpy (&sta_cmd.key.keys, keyconf->key, keyconf->keylen);
This should be fine though, only up to 16 bytes for CCMP.
drivers/net/wireless/intel/iwlwifi/dvm/sta.c static int iwlagn_send_sta_key(struct iwl_priv *priv, · line 1103
Quoted 7 lines
drivers/net/wireless/intel/iwlwifi/dvm/sta.c +1
-1case WLAN_CIPHER_SUITE_TKIP : key_flags |=STA_KEY_FLG_TKIP ; sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;for (i =0 ; i <5 ; i++) sta_cmd.key.tkip_rx_ttak[i] =cpu_to_le16 (tkip_p1k[i]); -memcpy (sta_cmd.key.key, keyconf->key, keyconf->keylen); +memcpy (&sta_cmd.key.keys, keyconf->key, keyconf->keylen);
And that's actually a bug, we should've copied only 16 bytes, I guess. DVM didn't support MIC offload anyway (at least the way Linux uses the firmware, though I thought it doesn't at all), so we don't need the MIC RX/TX keys in there, but anyway the sequence counter values are not part of the key material on the host.
I don't think I have a machine now to test this with (nor a TKIP AP, of course, but that could be changed) - but I suspect that since we actually calculate the TTAK above, we might not even need this memcpy() at all?
johannes
Quoted 23 lines · Johannes Berg
drivers/net/wireless/intel/iwlwifi/dvm/sta.c static int iwlagn_send_sta_key(struct iwl_priv *priv, · line 1096
Quoted 5 lines · Kees Cook
drivers/net/wireless/intel/iwlwifi/dvm/sta.c +1
-1case WLAN_CIPHER_SUITE_CCMP : key_flags |=STA_KEY_FLG_CCMP ; -memcpy (sta_cmd.key.key, keyconf->key, keyconf->keylen); +memcpy (&sta_cmd.key.keys, keyconf->key, keyconf->keylen);This should be fine though, only up to 16 bytes for CCMP.
drivers/net/wireless/intel/iwlwifi/dvm/sta.c static int iwlagn_send_sta_key(struct iwl_priv *priv, · line 1103
Quoted 7 lines
drivers/net/wireless/intel/iwlwifi/dvm/sta.c +1
-1case WLAN_CIPHER_SUITE_TKIP : key_flags |=STA_KEY_FLG_TKIP ; sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;for (i =0 ; i <5 ; i++) sta_cmd.key.tkip_rx_ttak[i] =cpu_to_le16 (tkip_p1k[i]); -memcpy (sta_cmd.key.key, keyconf->key, keyconf->keylen); +memcpy (&sta_cmd.key.keys, keyconf->key, keyconf->keylen);And that's actually a bug, we should've copied only 16 bytes, I guess. DVM didn't support MIC offload anyway (at least the way Linux uses the firmware, though I thought it doesn't at all), so we don't need the MIC RX/TX keys in there, but anyway the sequence counter values are not part of the key material on the host.
Quoted 4 lines
I don't think I have a machine now to test this with (nor a TKIP AP, of course, but that could be changed) - but I suspect that since we actually calculate the TTAK above, we might not even need this
memcpy()at all?
It's the latter that is triggered in the real world, though. See the referenced URL and also now on bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=217214
i.e.: drivers/net/wireless/intel/iwlwifi/dvm/sta.c:1103
So keyconf->keylen is coming in as 32. If this is a bug, I'm not sure where/how to fix it.
Perhaps this patch can be taken as-is, and a WARN_ON added for the >16 case to be tracked down separately?
Signature · 1 line
Kees Cook
Quoted 20 lines
Quoted 15 lines
drivers/net/wireless/intel/iwlwifi/dvm/sta.c static int iwlagn_send_sta_key(struct iwl_priv *priv, · line 1103
Quoted 8 lines
drivers/net/wireless/intel/iwlwifi/dvm/sta.c +1
-1case WLAN_CIPHER_SUITE_TKIP : key_flags |=STA_KEY_FLG_TKIP ; sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;for (i =0 ; i <5 ; i++) sta_cmd.key.tkip_rx_ttak[i] =cpu_to_le16 (tkip_p1k[i]); -memcpy (sta_cmd.key.key, keyconf->key, keyconf->keylen); +memcpy (&sta_cmd.key.keys, keyconf->key, keyconf->keylen);And that's actually a bug, we should've copied only 16 bytes, I guess. DVM didn't support MIC offload anyway (at least the way Linux uses the firmware, though I thought it doesn't at all), so we don't need the MIC RX/TX keys in there, but anyway the sequence counter values are not part of the key material on the host.
Quoted 4 lines
I don't think I have a machine now to test this with (nor a TKIP AP, of course, but that could be changed) - but I suspect that since we actually calculate the TTAK above, we might not even need this
memcpy()at all?
Quoted 7 lines
It's the latter that is triggered in the real world, though. See the referenced URL and also now on bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=217214
i.e.:drivers/net/wireless/intel/iwlwifi/dvm/sta.c:1103So
keyconf->keylenis coming in as 32. If this is a bug, I'm not sure where/how to fix it.
Yes, I know it's coming in as such - I believe it should be copying 16 bytes instead of the full keylen. TKIP keys are comprised of 16 bytes encryption/decryption key and 8 bytes TX/RX MIC keys for a total of 32, but since the device doesn't do MIC calculations, it only needs the first 16 bytes here (if even that, since we also give it the P1K which is derived from the TK...? maybe not even that)
But I guess we should test it ... not sure I still have a machine that takes these NICs (I do have NICs).
johannes
Quoted 35 lines · Johannes Berg
Quoted 20 lines
Quoted 15 lines
drivers/net/wireless/intel/iwlwifi/dvm/sta.c static int iwlagn_send_sta_key(struct iwl_priv *priv, · line 1103
Quoted 8 lines
drivers/net/wireless/intel/iwlwifi/dvm/sta.c +1
-1case WLAN_CIPHER_SUITE_TKIP : key_flags |=STA_KEY_FLG_TKIP ; sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;for (i =0 ; i <5 ; i++) sta_cmd.key.tkip_rx_ttak[i] =cpu_to_le16 (tkip_p1k[i]); -memcpy (sta_cmd.key.key, keyconf->key, keyconf->keylen); +memcpy (&sta_cmd.key.keys, keyconf->key, keyconf->keylen);And that's actually a bug, we should've copied only 16 bytes, I guess. DVM didn't support MIC offload anyway (at least the way Linux uses the firmware, though I thought it doesn't at all), so we don't need the MIC RX/TX keys in there, but anyway the sequence counter values are not part of the key material on the host.
Quoted 4 lines
I don't think I have a machine now to test this with (nor a TKIP AP, of course, but that could be changed) - but I suspect that since we actually calculate the TTAK above, we might not even need this
memcpy()at all?Quoted 7 lines
It's the latter that is triggered in the real world, though. See the referenced URL and also now on bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=217214
i.e.:drivers/net/wireless/intel/iwlwifi/dvm/sta.c:1103So
keyconf->keylenis coming in as 32. If this is a bug, I'm not sure where/how to fix it.Yes, I know it's coming in as such - I believe it should be copying 16 bytes instead of the full keylen. TKIP keys are comprised of 16 bytes encryption/decryption key and 8 bytes TX/RX MIC keys for a total of 32, but since the device doesn't do MIC calculations, it only needs the first 16 bytes here (if even that, since we also give it the P1K which is derived from the TK...? maybe not even that)
Quoted 2 lines
But I guess we should test it ... not sure I still have a machine that takes these NICs (I do have NICs).
What sort of patch would you like here? How should the other cases in the switch statement behave?
Are these the correct bounds?
WLAN_CIPHER_SUITE_CCMP: keylen <= 16 WLAN_CIPHER_SUITE_TKIP: keylen <= 16 WLAN_CIPHER_SUITE_WEP104: keylen <= 13 WLAN_CIPHER_SUITE_WEP40: keylen <= 13
and should it silently ignore larger values in each case?
Signature · 1 line
Kees Cook
Quoted 10 lines · Kees Cook
What sort of patch would you like here? How should the other cases in the switch statement behave?
Are these the correct bounds?
WLAN_CIPHER_SUITE_CCMP: keylen <= 16 WLAN_CIPHER_SUITE_TKIP: keylen <= 16 WLAN_CIPHER_SUITE_WEP104: keylen <= 13 WLAN_CIPHER_SUITE_WEP40: keylen <= 13
40 bits is only 5 bytes :-)
Quoted 2 lines
and should it silently ignore larger values in each case?
For the cases other than TKIP, no changes should be necessary - in those cases, the key will always be == the value from the (corrected) table above.
For TKIP, the keylen will be 32, but comprised of the actual encryption key and then MIC keys, so only 16 bytes should be relevant.
I don't really care how you handle this.
We can be bug-compatible with the old code, then I'd say from your patch only the changes in the TKIP case are needed.
Or we can just limit the copy to only 16 bytes, but that would need some validation that it still works. From memory, I'd say it will still work, and I'd even say the whole memcpy() might not be needed in the TKIP case at all since the iwldvm firmware deals with phase 1 keys (P1K) to derive phase 2 keys, not the original encryption key.
So simpler is probably to just take the TKIP hunk from your patch, even knowing that the memcpy() there is almost certainly incorrect now.
johannes