Hi Stefan, 

On Wed, 14 Aug 2019, Stefan Sperling wrote:

> On Tue, Aug 13, 2019 at 10:47:24AM -0300, Martin Pieuchot wrote:
> > if the crash is because of a missing key, put one :)
> 
> Yes, you've convinced me. With this patch we install the CCMP key
> to both firmware and net80211. Until firmware confirms that the
> key has been installed, we do software encrypt/decrypt.

I agree we should handle a missing key but suggest an alternative approach 
below.

I'm unconvinced the root cause is a race on loading the key: I tried to 
induce an infinite race, by skipping the command to upload the key to 
hardware, but couldn't reproduce the crash. I suspect the guard for 
handling hardware decryption in iwm_rx_rx_mpdu() is too weak, and a frame 
governed by the offloaded key is slipping through.

The immediate cause of the crash is that, unless the driver sets 
IEEE80211_RXI_HWDEC on all frames governed by a key, the stack will 
attempt software decryption without the necessary context and crash. i.e. 
software decryption is the default and the stack assumes this is always 
possible. But it isn't: the stack has delegated decryption to the driver.

So, evade this class of errors and check that software decrypt can handle 
a key, i.e that ieee8021_set_key() has been called, and drop the frame if 
not. (see below; compiled but untested.)

Thoughts? 

best, 
Richard. 

iwm0 at pci1 dev 0 function 0 "Intel Dual Band Wireless AC 7265" rev 0x69, msi
iwm0: hw rev 0x210, fw ver 16.242414.0, address xx:xx:xx:xx:xx:xx 

Index: net80211/ieee80211_crypto.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_crypto.c,v
retrieving revision 1.74
diff -u -p -u -p -r1.74 ieee80211_crypto.c
--- net80211/ieee80211_crypto.c 24 Sep 2018 20:14:59 -0000      1.74
+++ net80211/ieee80211_crypto.c 15 Aug 2019 01:12:28 -0000
@@ -157,6 +157,10 @@ ieee80211_set_key(struct ieee80211com *i
                /* should not get there */
                error = EINVAL;
        }
+
+       if (error == 0)
+               k->k_flags |= IEEE80211_KEY_SWCRYPTO;
+
        return error;
 }
 
@@ -280,6 +284,11 @@ ieee80211_decrypt(struct ieee80211com *i
                }
                k = &ic->ic_nw_keys[kid];
        }
+
+       if ((k->k_flags & IEEE80211_KEY_SWCRYPTO) == 0) {
+               goto err;
+       }
+
        switch (k->k_cipher) {
        case IEEE80211_CIPHER_WEP40:
        case IEEE80211_CIPHER_WEP104:
@@ -296,9 +305,15 @@ ieee80211_decrypt(struct ieee80211com *i
                break;
        default:
                /* key not defined */
-               m_freem(m0);
-               m0 = NULL;
+               goto err;
        }
+
+       return m0;
+
+err:
+       m0 = NULL;
+       m_freem(m0);
+
        return m0;
 }
 
Index: net80211/ieee80211_crypto.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_crypto.h,v
retrieving revision 1.25
diff -u -p -u -p -r1.25 ieee80211_crypto.h
--- net80211/ieee80211_crypto.h 18 Aug 2017 17:30:12 -0000      1.25
+++ net80211/ieee80211_crypto.h 15 Aug 2019 01:12:28 -0000
@@ -78,6 +78,7 @@ struct ieee80211_key {
 #define IEEE80211_KEY_GROUP    0x00000001      /* group data key */
 #define IEEE80211_KEY_TX       0x00000002      /* Tx+Rx */
 #define IEEE80211_KEY_IGTK     0x00000004      /* integrity group key */
+#define IEEE80211_KEY_SWCRYPTO 0x00000080      /* loaded for software crypto */
 
        u_int                   k_len;
        u_int64_t               k_rsc[IEEE80211_NUM_TID];

-----------------------------------------------
illustration of disabling key upload below here
-----------------------------------------------


Index: dev/pci/if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.244
diff -u -p -u -p -r1.244 if_iwm.c
--- dev/pci/if_iwm.c    8 Aug 2019 13:56:56 -0000       1.244
+++ dev/pci/if_iwm.c    14 Aug 2019 20:32:47 -0000
@@ -6088,7 +6088,7 @@ int
 iwm_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
     struct ieee80211_key *k)
 {
-       struct iwm_softc *sc = ic->ic_softc;
+       // struct iwm_softc *sc = ic->ic_softc;
        struct iwm_add_sta_key_cmd cmd = { 0 };
 
        if ((k->k_flags & IEEE80211_KEY_GROUP) ||
@@ -6108,8 +6108,10 @@ iwm_set_key(struct ieee80211com *ic, str
        cmd.key_offset = 0;
        cmd.sta_id = IWM_STATION_ID;
 
-       return iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC,
-           sizeof(cmd), &cmd);
+       // return iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC,
+       //    sizeof(cmd), &cmd);
+
+       return 0;
 }
 
 void


> 
> Should the firmware fail to install the key for some reason, we will
> just keep using our software fallback until the interface is reset.
> 
> This also fixes the race with incoming frames during WPA handshake,
> i.e. while (ni->ni_flags & IEEE80211_NODE_RXPROT) == 0.
> Such frames can be passed to net80211 and will be dropped there.
> 
> Lightly tested on a 7260 device.
> 
> Ok?
> 
> diff refs/heads/master refs/heads/ccmp-crash2
> blob - 038e6a63dfff113b525bb1e9a30c935996535569
> blob + 8afcce065eb0d85f4469a3f378cacba1513bc215
> --- sys/dev/pci/if_iwm.c
> +++ sys/dev/pci/if_iwm.c
> @@ -3595,10 +3595,17 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
>       rxi.rxi_rssi = rssi;
>       rxi.rxi_tstamp = device_timestamp;
>  
> -     /* Handle hardware decryption. */
> +     /*
> +      * Handle hardware decryption.
> +      *
> +      * If the WPA handshake has completed but firmware is not yet ready
> +      * to decrypt frames, fall back to software decryption in net80211. 
> +      * net80211 will drop encrypted frames until the handshake completes.
> +      */
>       if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL)
>           && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
>           !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
> +         (sc->sc_flags & IWM_FLAG_CCMP_READY) &&
>           (ni->ni_flags & IEEE80211_NODE_RXPROT) &&
>           ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) {
>               if ((rx_pkt_status & IWM_RX_MPDU_RES_STATUS_SEC_ENC_MSK) !=
> @@ -4402,7 +4409,8 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ie
>  
>       if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
>               k = ieee80211_get_txkey(ic, wh, ni);
> -             if  (k->k_cipher != IEEE80211_CIPHER_CCMP) {
> +             if  (k->k_cipher != IEEE80211_CIPHER_CCMP ||
> +                 (sc->sc_flags & IWM_FLAG_CCMP_READY) == 0) {
>                       if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
>                               return ENOBUFS;
>  
> @@ -4418,7 +4426,8 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ie
>       /* Copy 802.11 header in TX command. */
>       memcpy(((uint8_t *)tx) + sizeof(*tx), wh, hdrlen);
>  
> -     if  (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP) {
> +     if  (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP &&
> +         (sc->sc_flags & IWM_FLAG_CCMP_READY)) {
>               /* Trim 802.11 header and prepend CCMP IV. */
>               m_adj(m, hdrlen - IEEE80211_CCMP_HDRLEN);
>               ivp = mtod(m, u_int8_t *);
> @@ -6090,6 +6099,7 @@ iwm_set_key(struct ieee80211com *ic, struct ieee80211_
>  {
>       struct iwm_softc *sc = ic->ic_softc;
>       struct iwm_add_sta_key_cmd cmd = { 0 };
> +     int err;
>  
>       if ((k->k_flags & IEEE80211_KEY_GROUP) ||
>           k->k_cipher != IEEE80211_CIPHER_CCMP)  {
> @@ -6097,6 +6107,8 @@ iwm_set_key(struct ieee80211com *ic, struct ieee80211_
>               return (ieee80211_set_key(ic, ni, k));
>       }
>  
> +     sc->sc_flags &= ~(IWM_FLAG_CCMP_READY | IWM_FLAG_CCMP_KEY_SENT);
> +
>       cmd.key_flags = htole16(IWM_STA_KEY_FLG_CCM |
>           IWM_STA_KEY_FLG_WEP_KEY_MAP |
>           ((k->k_id << IWM_STA_KEY_FLG_KEYID_POS) &
> @@ -6108,8 +6120,15 @@ iwm_set_key(struct ieee80211com *ic, struct ieee80211_
>       cmd.key_offset = 0;
>       cmd.sta_id = IWM_STATION_ID;
>  
> -     return iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC,
> -         sizeof(cmd), &cmd);
> +     /* Allow for software CCMP encryption/decryption fallback. */
> +     err = ieee80211_set_key(ic, ni, k);
> +     if (!err) {
> +             err = iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC,
> +                 sizeof(cmd), &cmd);
> +             if (!err)
> +                     sc->sc_flags |= IWM_FLAG_CCMP_KEY_SENT;
> +     }
> +     return err;
>  }
>  
>  void
> @@ -6135,6 +6154,10 @@ iwm_delete_key(struct ieee80211com *ic, struct ieee802
>       cmd.sta_id = IWM_STATION_ID;
>  
>       iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC, sizeof(cmd), &cmd);
> +     sc->sc_flags &= ~(IWM_FLAG_CCMP_KEY_SENT | IWM_FLAG_CCMP_READY);
> +
> +     /* Delete software fallback CCMP key. */
> +        ieee80211_delete_key(ic, ni, k);
>  }
>  
>  void
> @@ -6846,6 +6869,7 @@ iwm_stop(struct ifnet *ifp)
>       sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE;
>       sc->sc_flags &= ~IWM_FLAG_HW_ERR;
>       sc->sc_flags &= ~IWM_FLAG_SHUTDOWN;
> +     sc->sc_flags &= ~(IWM_FLAG_CCMP_KEY_SENT | IWM_FLAG_CCMP_READY);
>  
>       sc->sc_newstate(ic, IEEE80211_S_INIT, -1);
>  
> @@ -7331,6 +7355,12 @@ iwm_notif_intr(struct iwm_softc *sc)
>                       break;
>  
>               case IWM_ADD_STA_KEY:
> +                     if (sc->sc_flags & IWM_FLAG_CCMP_KEY_SENT) {
> +                             sc->sc_flags |= IWM_FLAG_CCMP_READY;
> +                             sc->sc_flags &= ~IWM_FLAG_CCMP_KEY_SENT;
> +                     }
> +                     break;
> +
>               case IWM_PHY_CONFIGURATION_CMD:
>               case IWM_TX_ANT_CONFIGURATION_CMD:
>               case IWM_ADD_STA:
> blob - e6593fbc840833a36d5a792042faaa85e3ac9719
> blob + 747616074f868d8679f9f01232dec4ce09474f93
> --- sys/dev/pci/if_iwmvar.h
> +++ sys/dev/pci/if_iwmvar.h
> @@ -289,6 +289,8 @@ struct iwm_rx_ring {
>  #define IWM_FLAG_HW_ERR              0x80    /* hardware error occurred */
>  #define IWM_FLAG_SHUTDOWN    0x100   /* shutting down; new tasks forbidden */
>  #define IWM_FLAG_BGSCAN              0x200   /* background scan in progress 
> */
> +#define IWM_FLAG_CCMP_KEY_SENT       0x400   /* CCMP key sent to firmware */
> +#define IWM_FLAG_CCMP_READY  0x800   /* CCMP key installed in firmware */
>  
>  struct iwm_ucode_status {
>       uint32_t uc_error_event_table;
> 
> 

Reply via email to