2023-07-14 22:58:45

by Polaris Pi

[permalink] [raw]
Subject: [PATCH v6] wifi: mwifiex: Fix OOB and integer underflow when rx packets

Make sure mwifiex_process_mgmt_packet and its callers
mwifiex_process_sta_rx_packet and mwifiex_process_uap_rx_packet
not out-of-bounds access the skb->data buffer.

Fixes: 2dbaf751b1de ("mwifiex: report received management frames to cfg80211")
Signed-off-by: Polaris Pi <[email protected]>
---
V5: Follow chromeos comments: preserve the original flow of mwifiex_process_uap_rx_packet
V6: Simplify check in mwifiex_process_uap_rx_packet
---
drivers/net/wireless/marvell/mwifiex/sta_rx.c | 3 ++-
drivers/net/wireless/marvell/mwifiex/uap_txrx.c | 10 ++++++++++
drivers/net/wireless/marvell/mwifiex/util.c | 5 +++++
3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/sta_rx.c b/drivers/net/wireless/marvell/mwifiex/sta_rx.c
index 13659b02ba88..88aaec645291 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_rx.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_rx.c
@@ -194,7 +194,8 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,

rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;

- if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
+ if ((rx_pkt_offset + rx_pkt_length) > (u16)skb->len ||
+ skb->len - rx_pkt_offset < sizeof(*rx_pkt_hdr)) {
mwifiex_dbg(adapter, ERROR,
"wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
skb->len, rx_pkt_offset, rx_pkt_length);
diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
index e495f7eaea03..f0711b73ba3e 100644
--- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
+++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
@@ -367,6 +367,16 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);

+ if (le16_to_cpu(uap_rx_pd->rx_pkt_offset) + sizeof(*rx_pkt_hdr) > skb->len) {
+ mwifiex_dbg(adapter, ERROR,
+ "wrong rx packet offset: len=%d, offset=%d\n",
+ skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
+ priv->stats.rx_dropped++;
+
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source);

if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
index 94c2d219835d..31e1a82883e4 100644
--- a/drivers/net/wireless/marvell/mwifiex/util.c
+++ b/drivers/net/wireless/marvell/mwifiex/util.c
@@ -399,6 +399,11 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,

pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);

+ if (pkt_len < sizeof(struct ieee80211_hdr) || skb->len < pkt_len) {
+ mwifiex_dbg(priv->adapter, ERROR, "invalid rx_pkt_length");
+ return -1;
+ }
+
ieee_hdr = (void *)skb->data;
if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
--
2.25.1



2023-07-15 21:32:24

by Matthew Wang

[permalink] [raw]
Subject: Re: [PATCH v6] wifi: mwifiex: Fix OOB and integer underflow when rx packets

Reviewed-by: Matthew Wang <[email protected]>

On Sat, Jul 15, 2023 at 12:48 AM Polaris Pi <[email protected]> wrote:
>
> Make sure mwifiex_process_mgmt_packet and its callers
> mwifiex_process_sta_rx_packet and mwifiex_process_uap_rx_packet
> not out-of-bounds access the skb->data buffer.
>
> Fixes: 2dbaf751b1de ("mwifiex: report received management frames to cfg80211")
> Signed-off-by: Polaris Pi <[email protected]>
> ---
> V5: Follow chromeos comments: preserve the original flow of mwifiex_process_uap_rx_packet
> V6: Simplify check in mwifiex_process_uap_rx_packet
> ---
> drivers/net/wireless/marvell/mwifiex/sta_rx.c | 3 ++-
> drivers/net/wireless/marvell/mwifiex/uap_txrx.c | 10 ++++++++++
> drivers/net/wireless/marvell/mwifiex/util.c | 5 +++++
> 3 files changed, 17 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/marvell/mwifiex/sta_rx.c b/drivers/net/wireless/marvell/mwifiex/sta_rx.c
> index 13659b02ba88..88aaec645291 100644
> --- a/drivers/net/wireless/marvell/mwifiex/sta_rx.c
> +++ b/drivers/net/wireless/marvell/mwifiex/sta_rx.c
> @@ -194,7 +194,8 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
>
> rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
>
> - if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
> + if ((rx_pkt_offset + rx_pkt_length) > (u16)skb->len ||
> + skb->len - rx_pkt_offset < sizeof(*rx_pkt_hdr)) {
> mwifiex_dbg(adapter, ERROR,
> "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
> skb->len, rx_pkt_offset, rx_pkt_length);
> diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
> index e495f7eaea03..f0711b73ba3e 100644
> --- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
> +++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
> @@ -367,6 +367,16 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
> rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
> rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
>
> + if (le16_to_cpu(uap_rx_pd->rx_pkt_offset) + sizeof(*rx_pkt_hdr) > skb->len) {
> + mwifiex_dbg(adapter, ERROR,
> + "wrong rx packet offset: len=%d, offset=%d\n",
> + skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
> + priv->stats.rx_dropped++;
> +
> + dev_kfree_skb_any(skb);
> + return 0;
> + }
> +
> ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source);
>
> if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
> diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
> index 94c2d219835d..31e1a82883e4 100644
> --- a/drivers/net/wireless/marvell/mwifiex/util.c
> +++ b/drivers/net/wireless/marvell/mwifiex/util.c
> @@ -399,6 +399,11 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
>
> pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
>
> + if (pkt_len < sizeof(struct ieee80211_hdr) || skb->len < pkt_len) {
> + mwifiex_dbg(priv->adapter, ERROR, "invalid rx_pkt_length");
> + return -1;
> + }
> +
> ieee_hdr = (void *)skb->data;
> if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
> if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
> --
> 2.25.1
>

2023-07-17 14:13:23

by Polaris Pi

[permalink] [raw]
Subject: Re: [PATCH v6] wifi: mwifiex: Fix OOB and integer underflow when rx packets

Hi Jakub,

This patch has been reviewed by chromeos wifi team, and review tag has been added by their tech leader.
Could you please review it again?

Thanks!

2023-07-17 21:57:19

by Jakub Kicinski

[permalink] [raw]
Subject: Re: [PATCH v6] wifi: mwifiex: Fix OOB and integer underflow when rx packets

On Mon, 17 Jul 2023 14:02:32 +0000 Polaris Pi wrote:
> Hi Jakub,
>
> This patch has been reviewed by chromeos wifi team, and review tag
> has been added by their tech leader.
> Could you please review it again?

Looks fine, I'll leave it to the wireless maintainer to process
once they are back from their vacation. It doesn't look very urgent
to me.

2023-07-20 21:53:45

by Matthew Wang

[permalink] [raw]
Subject: Re: [PATCH v6] wifi: mwifiex: Fix OOB and integer underflow when rx packets

> diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
> index 94c2d219835d..31e1a82883e4 100644
> --- a/drivers/net/wireless/marvell/mwifiex/util.c
> +++ b/drivers/net/wireless/marvell/mwifiex/util.c
> @@ -399,6 +399,11 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
>
> pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
>
> + if (pkt_len < sizeof(struct ieee80211_hdr) || skb->len < pkt_len) {

I've tested this patch a bit on a ChromeOS device and I've noticed
empirically that skb->len is often (always?) two less than pkt_len,
implying that pkt_len actually includes the rx_pkt_length field as
well (note that pkt_len gets adjusted by ETH_ALEN + sizeof(pkt_len)
below), so we end up hitting this condition reliably in certain
situations. This probably means the memmove below is not entirely
correct, but either way I don't think this patch is correct on its
own.

Consider my Reviewed-by tag removed until this gets resolved.

> + mwifiex_dbg(priv->adapter, ERROR, "invalid rx_pkt_length");
> + return -1;
> + }
> +
> ieee_hdr = (void *)skb->data;
> if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
> if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
> --