From afc857bc2a71905b23bbe1894dbadb2915a3ac4d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 Jan 2021 13:10:28 +0200 Subject: iwlwifi: mvm: add notification size checks We shouldn't trust the firmware with the sizes (or contents) of notifications, accessing too much data could cause page faults if the data doesn't fit into the allocated space. This applies more on older NICs where multiple notifications can be in a single RX buffer. Add a general framework for checking a minimum size of any notification in the RX handlers and use it for most. Some RX handlers were already checking and I've moved the checks, some more complex checks I left and made them _NO_SIZE for the RX handlers. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210117130510.3e155d5e5f90.I2121fa4ac7cd7eb98970d84b793796646afa3eed@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 9078fcb5286c..fd5e08961651 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1289,6 +1289,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); + unsigned int pkt_len = iwl_rx_packet_payload_len(pkt); struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; struct iwl_extended_beacon_notif_v5 *beacon_v5 = (void *)pkt->data; struct ieee80211_vif *csa_vif; @@ -1304,6 +1305,9 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_mvm_tx_resp *beacon_notify_hdr = &beacon_v5->beacon_notify_hdr; + if (unlikely(pkt_len < sizeof(*beacon_v5))) + return; + mvm->ibss_manager = beacon_v5->ibss_mgr_status != 0; agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr); status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK; @@ -1314,6 +1318,9 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, mvm->ap_last_beacon_gp2, le32_to_cpu(beacon_notify_hdr->initial_rate)); } else { + if (unlikely(pkt_len < sizeof(*beacon))) + return; + mvm->ibss_manager = beacon->ibss_mgr_status != 0; status = le32_to_cpu(beacon->status) & TX_STATUS_MSK; IWL_DEBUG_RX(mvm, @@ -1419,12 +1426,13 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); + unsigned int pkt_len = iwl_rx_packet_payload_len(pkt); struct iwl_stored_beacon_notif *sb = (void *)pkt->data; struct ieee80211_rx_status rx_status; struct sk_buff *skb; u32 size = le32_to_cpu(sb->byte_count); - if (size == 0) + if (size == 0 || pkt_len < struct_size(sb, data, size)) return; skb = alloc_skb(size, GFP_ATOMIC); @@ -1460,14 +1468,10 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_probe_resp_data_notif *notif = (void *)pkt->data; struct iwl_probe_resp_data *old_data, *new_data; - int len = iwl_rx_packet_payload_len(pkt); u32 id = le32_to_cpu(notif->mac_id); struct ieee80211_vif *vif; struct iwl_mvm_vif *mvmvif; - if (WARN_ON_ONCE(len < sizeof(*notif))) - return; - IWL_DEBUG_INFO(mvm, "Probe response data notif: noa %d, csa %d\n", notif->noa_active, notif->csa_counter); @@ -1514,12 +1518,8 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data; struct ieee80211_vif *csa_vif, *vif; struct iwl_mvm_vif *mvmvif; - int len = iwl_rx_packet_payload_len(pkt); u32 id_n_color, csa_id, mac_id; - if (WARN_ON_ONCE(len < sizeof(*notif))) - return; - id_n_color = le32_to_cpu(notif->id_and_color); mac_id = id_n_color & FW_CTXT_ID_MSK; -- cgit v1.2.3