wifi: mwifiex: Fix tlv_buf_left calculation and replace one-element array
v2 cover wifi: mwifiex: Fix tlv_buf_left calculation and replace one-element array
Hi all!
This small series is aimed at fixing a bug in the tlv_buf_left calculation, doing a flexible-array transformation, and adding a couple of sanity checks.
Thanks
Changes in v2:
- Fix format specifier in patch 3/3: %ld -> %zu
- Update warning messages to explicitly mention that TLV size is greater than tlv_buf_len in patch 3/3.
v1:
- Link: https://lore.kernel.org/linux-hardening/[email protected]/
Gustavo A. R. Silva (3):
wifi: mwifiex: Fix tlv_buf_left calculation
wifi: mwifiex: Replace one-element array with flexible-array member in
struct mwifiex_ie_types_rxba_sync
wifi: mwifiex: Sanity check tlv_len and tlv_bitmap_len
.../wireless/marvell/mwifiex/11n_rxreorder.c | 22 ++++++++++++++++--- drivers/net/wireless/marvell/mwifiex/fw.h | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-)
Signature · 1 line
2.34.1
PATCH v2 1/3 wifi: mwifiex: Fix tlv_buf_left calculation
In a TLV encoding scheme, the Length part represents the length after the header containing the values for type and length. In this case, tlv_len should be:
tlv_len == (sizeof(*tlv_rxba) - 1) - sizeof(tlv_rxba->header) + tlv_bitmap_len
Notice that the - 1 accounts for the one-element array bitmap, which 1-byte size is already included in sizeof(*tlv_rxba).
So, if the above is correct, there is a double-counting of some members in struct mwifiex_ie_types_rxba_sync, when tlv_buf_left and tmp are calculated:
968 tlv_buf_left -= (sizeof(*tlv_rxba) + tlv_len);
969 tmp = (u8 *)tlv_rxba + tlv_len + sizeof(*tlv_rxba);
in specific, members:
drivers/net/wireless/marvell/mwifiex/fw.h:777
777 u8 mac[ETH_ALEN]; 778 u8 tid; 779 u8 reserved; 780 __le16 seq_num; 781 __le16 bitmap_len;
This is clearly wrong, and affects the subsequent decoding of data in event_buf through tlv_rxba:
970 tlv_rxba = (struct mwifiex_ie_types_rxba_sync *)tmp;
Fix this by using sizeof(tlv_rxba->header) instead of sizeof(*tlv_rxba) in the calculation of tlv_buf_left and tmp.
This results in the following binary differences before/after changes:
| drivers/net/wireless/marvell/mwifiex/11n_rxreorder.o | @@ -4698,11 +4698,11 @@ | drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c:968 | tlv_buf_left -= (sizeof(tlv_rxba->header) + tlv_len); | - 1da7: lea -0x11(%rbx),%edx | + 1da7: lea -0x4(%rbx),%edx | 1daa: movzwl %bp,%eax | drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c:969 | tmp = (u8 *)tlv_rxba + sizeof(tlv_rxba->header) + tlv_len; | - 1dad: lea 0x11(%r15,%rbp,1),%r15 | + 1dad: lea 0x4(%r15,%rbp,1),%r15
The above reflects the desired change: avoid counting 13 too many bytes; which is the total size of the double-counted members in struct mwifiex_ie_types_rxba_sync:
$ pahole -C mwifiex_ie_types_rxba_sync drivers/net/wireless/marvell/mwifiex/11n_rxreorder.o
struct mwifiex_ie_types_rxba_sync {
struct mwifiex_ie_types_header header; /* 0 4 */ |-----------------------------------------------------------------------
| u8 mac[6]; /* 4 6 */ |
| u8 tid; /* 10 1 */ |
| u8 reserved; /* 11 1 */ |
| __le16 seq_num; /* 12 2 */ |
| __le16 bitmap_len; /* 14 2 */ |
| u8 bitmap[1]; /* 16 1 */ |
|----------------------------------------------------------------------|
| 13 bytes|
-----------
/* size: 17, cachelines: 1, members: 7 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));---
Changes in v2:
- Fix typo in changelog text: s/too bytes/too many bytes
- Update binary diff snapshot in changelog text.
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +2 -2
@@ -965,8 +965,8 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv, } } - tlv_buf_left -= (sizeof (*tlv_rxba) + tlv_len); - tmp = (u8 *)tlv_rxba + tlv_len +sizeof (*tlv_rxba); + tlv_buf_left -= (sizeof (tlv_rxba->header) + tlv_len); + tmp = (u8 *)tlv_rxba +sizeof (tlv_rxba->header) + tlv_len; tlv_rxba = (struct mwifiex_ie_types_rxba_sync *)tmp; } }
Signature · 1 line
2.34.1
Re: [PATCH v2 1/3] wifi: mwifiex: Fix tlv_buf_left calculation
Quoted 70 lines · Gustavo A. R. Silva
In a TLV encoding scheme, the Length part represents the length after the header containing the values for type and length. In this case,
tlv_lenshould be:
tlv_len== (sizeof(*tlv_rxba)- 1) -sizeof(tlv_rxba->header)+tlv_bitmap_lenNotice that the
- 1accounts for the one-element arraybitmap, which 1-byte size is already included insizeof(*tlv_rxba).So, if the above is correct, there is a double-counting of some members in
struct mwifiex_ie_types_rxba_sync, whentlv_buf_leftandtmpare calculated:968
tlv_buf_left-= (sizeof(*tlv_rxba)+tlv_len);
969 tmp = (u8 *)tlv_rxba +tlv_len+sizeof(*tlv_rxba);in specific, members:
drivers/net/wireless/marvell/mwifiex/fw.h:777777 u8 mac[ETH_ALEN]; 778 u8 tid; 779 u8 reserved; 780 __le16 seq_num; 781 __le16 bitmap_len;This is clearly wrong, and affects the subsequent decoding of data in
event_bufthroughtlv_rxba:970
tlv_rxba= (structmwifiex_ie_types_rxba_sync*)tmp;Fix this by using
sizeof(tlv_rxba->header)instead ofsizeof(*tlv_rxba)in the calculation oftlv_buf_leftandtmp.This results in the following binary differences before/after changes:
| drivers/net/wireless/marvell/mwifiex/11n_rxreorder.o | @@ -4698,11 +4698,11 @@ | drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c:968 | tlv_buf_left -= (sizeof(tlv_rxba->header) + tlv_len); | - 1da7: lea -0x11(%rbx),%edx | + 1da7: lea -0x4(%rbx),%edx | 1daa: movzwl %bp,%eax | drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c:969 | tmp = (u8 *)tlv_rxba + sizeof(tlv_rxba->header) + tlv_len; | - 1dad: lea 0x11(%r15,%rbp,1),%r15 | + 1dad: lea 0x4(%r15,%rbp,1),%r15The above reflects the desired change: avoid counting 13 too many bytes; which is the total size of the double-counted members in
struct mwifiex_ie_types_rxba_sync:$ pahole -C mwifiex_ie_types_rxba_sync drivers/net/wireless/marvell/mwifiex/11n_rxreorder.o struct mwifiex_ie_types_rxba_sync { struct mwifiex_ie_types_header header; /* 0 4 */|----------------------------------------------------------------------- | u8 mac[6]; /* 4 6 */ | | u8 tid; /* 10 1 */ | | u8 reserved; /* 11 1 */ | | __le16 seq_num; /* 12 2 */ | | __le16 bitmap_len; /* 14 2 */ | | u8 bitmap[1]; /* 16 1 */ | |----------------------------------------------------------------------| | 13 bytes| ----------- /* size: 17, cachelines: 1, members: 7 */ /* last cacheline: 17 bytes */ } __attribute__((__packed__));
Quoted 3 lines
Fixes 99ffe72cdae4 ("mwifiex: process rxba_sync event")Signed-off-by Gustavo A. R. Silva <[email protected]>
Excellent commit log!
Signature · 1 line
Kees Cook
Re: [PATCH v2 1/3] wifi: mwifiex: Fix tlv_buf_left calculation
In reply to Gustavo A. R. SilvaQuoted 70 lines · Gustavo A. R. Silva
In a TLV encoding scheme, the Length part represents the length after the header containing the values for type and length. In this case,
tlv_lenshould be:
tlv_len== (sizeof(*tlv_rxba)- 1) -sizeof(tlv_rxba->header)+tlv_bitmap_lenNotice that the
- 1accounts for the one-element arraybitmap, which 1-byte size is already included insizeof(*tlv_rxba).So, if the above is correct, there is a double-counting of some members in
struct mwifiex_ie_types_rxba_sync, whentlv_buf_leftandtmpare calculated:968
tlv_buf_left-= (sizeof(*tlv_rxba)+tlv_len);
969 tmp = (u8 *)tlv_rxba +tlv_len+sizeof(*tlv_rxba);in specific, members:
drivers/net/wireless/marvell/mwifiex/fw.h:777777 u8 mac[ETH_ALEN]; 778 u8 tid; 779 u8 reserved; 780 __le16 seq_num; 781 __le16 bitmap_len;This is clearly wrong, and affects the subsequent decoding of data in
event_bufthroughtlv_rxba:970
tlv_rxba= (structmwifiex_ie_types_rxba_sync*)tmp;Fix this by using
sizeof(tlv_rxba->header)instead ofsizeof(*tlv_rxba)in the calculation oftlv_buf_leftandtmp.This results in the following binary differences before/after changes:
| drivers/net/wireless/marvell/mwifiex/11n_rxreorder.o | @@ -4698,11 +4698,11 @@ | drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c:968 | tlv_buf_left -= (sizeof(tlv_rxba->header) + tlv_len); | - 1da7: lea -0x11(%rbx),%edx | + 1da7: lea -0x4(%rbx),%edx | 1daa: movzwl %bp,%eax | drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c:969 | tmp = (u8 *)tlv_rxba + sizeof(tlv_rxba->header) + tlv_len; | - 1dad: lea 0x11(%r15,%rbp,1),%r15 | + 1dad: lea 0x4(%r15,%rbp,1),%r15The above reflects the desired change: avoid counting 13 too many bytes; which is the total size of the double-counted members in
struct mwifiex_ie_types_rxba_sync:$ pahole -C mwifiex_ie_types_rxba_sync drivers/net/wireless/marvell/mwifiex/11n_rxreorder.o struct mwifiex_ie_types_rxba_sync { struct mwifiex_ie_types_header header; /* 0 4 */|----------------------------------------------------------------------- | u8 mac[6]; /* 4 6 */ | | u8 tid; /* 10 1 */ | | u8 reserved; /* 11 1 */ | | __le16 seq_num; /* 12 2 */ | | __le16 bitmap_len; /* 14 2 */ | | u8 bitmap[1]; /* 16 1 */ | |----------------------------------------------------------------------| | 13 bytes| ----------- /* size: 17, cachelines: 1, members: 7 */ /* last cacheline: 17 bytes */ } __attribute__((__packed__));
Quoted 4 lines
Fixes 99ffe72cdae4 ("mwifiex: process rxba_sync event")Signed-off-by Gustavo A. R. Silva <[email protected]>Reviewed-by Kees Cook <[email protected]>
3 patches applied to wireless.git, thanks.
eec679e4ac5f wifi: mwifiex: Fix tlv_buf_left calculationc7847241de28 wifi: mwifiex: Replace one-element array with flexible-array member in struct mwifiex_ie_types_rxba_sync d5a93b7d2877 wifi: mwifiex: Sanity check tlv_len and tlv_bitmap_len
Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/patch/06668edd68e7a26bbfeebd1201ae077a2a7a8bce.1692931954.git.gustavoars@kernel.org/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Re: [PATCH v2 1/3] wifi: mwifiex: Fix tlv_buf_left calculation
Quoted 2 lines
3 patches applied to wireless.git, thanks.
Awesome. :)
Quoted 5 lines
eec679e4ac5fwifi: mwifiex: Fixtlv_buf_leftcalculationc7847241de28wifi: mwifiex: Replace one-element array with flexible-array member in structmwifiex_ie_types_rxba_syncd5a93b7d2877wifi: mwifiex: Sanity checktlv_lenandtlv_bitmap_len
Thanks!
--
Gustavo
PATCH v2 2/3 wifi: mwifiex: Replace one-element array with flexible-array member in struct mwifiex_ie_types_rxba_sync
In reply to Gustavo A. R. SilvaOne-element and zero-length arrays are deprecated. So, replace one-element array in struct mwifiex_ie_types_rxba_sync with flexible-array member, and refactor the rest of the code, accordingly.
This results in no differences in binary output.
---
Changes in v2:
- None.
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | 2 +- drivers/net/wireless/marvell/mwifiex/fw.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +1 -1
@@ -918,7 +918,7 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,mwifiex_dbg_dump (priv->adapter,EVT_D ,"RXBA_SYNC event:" , event_buf, len); -while (tlv_buf_left >=sizeof (*tlv_rxba)) { +while (tlv_buf_left >sizeof (*tlv_rxba)) { tlv_type =le16_to_cpu (tlv_rxba->header.type); tlv_len =le16_to_cpu (tlv_rxba->header.len);if (tlv_type !=TLV_TYPE_RXBA_SYNC ) {
drivers/net/wireless/marvell/mwifiex/fw.h +1 -1
@@ -779,7 +779,7 @@ struct mwifiex_ie_types_rxba_sync {u8 reserved;__le16 seq_num;__le16 bitmap_len; -u8 bitmap[1 ]; +u8 bitmap[]; } __packed;struct chan_band_param_set {
Signature · 1 line
2.34.1
Re: [PATCH v2 2/3] wifi: mwifiex: Replace one-element array with flexible-array member in struct mwifiex_ie_types_rxba_sync
Quoted 7 lines · Gustavo A. R. Silva
One-element and zero-length arrays are deprecated. So, replace one-element array in struct
mwifiex_ie_types_rxba_syncwith flexible-array member, and refactor the rest of the code, accordingly.This results in no differences in binary output.
Signed-off-by Gustavo A. R. Silva <[email protected]>
Signature · 1 line
Kees Cook
PATCH v2 3/3 wifi: mwifiex: Sanity check tlv_len and tlv_bitmap_len
In reply to Gustavo A. R. SilvaAdd sanity checks for both tlv_len and tlv_bitmap_len before decoding data from event_buf.
This prevents any malicious or buggy firmware from overflowing event_buf through large values for tlv_len and tlv_bitmap_len.
---
Changes in v2:
- Fix format specifier: %ld -> %zu
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
- Update warning messages to explicitly mention that TLV size is greater than tlv_buf_len.
.../net/wireless/marvell/mwifiex/11n_rxreorder.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +16 -0
@@ -921,6 +921,14 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,while (tlv_buf_left >sizeof (*tlv_rxba)) { tlv_type =le16_to_cpu (tlv_rxba->header.type); tlv_len =le16_to_cpu (tlv_rxba->header.len); +if (size_add (sizeof (tlv_rxba->header), tlv_len) > tlv_buf_left) { +mwifiex_dbg (priv->adapter,WARN , +"TLV size (%zu) overflows event_buf buf_left=%d\n" , +size_add (sizeof (tlv_rxba->header), tlv_len), + tlv_buf_left); +return ; + } +if (tlv_type !=TLV_TYPE_RXBA_SYNC ) {mwifiex_dbg (priv->adapter,ERROR ,"Wrong TLV id=0x%x\n" , tlv_type);
@@ -929,6 +937,14 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv, tlv_seq_num =le16_to_cpu (tlv_rxba->seq_num); tlv_bitmap_len =le16_to_cpu (tlv_rxba->bitmap_len); +if (size_add (sizeof (*tlv_rxba), tlv_bitmap_len) > tlv_buf_left) { +mwifiex_dbg (priv->adapter,WARN , +"TLV size (%zu) overflows event_buf buf_left=%d\n" , +size_add (sizeof (*tlv_rxba), tlv_bitmap_len), + tlv_buf_left); +return ; + } + mwifiex_dbg(priv->adapter, INFO, "%pM tid=%d seq_num=%d bitmap_len=%d\n", tlv_rxba->mac, tlv_rxba->tid, tlv_seq_num,
Signature · 1 line
2.34.1
Re: [PATCH v2 3/3] wifi: mwifiex: Sanity check tlv_len and tlv_bitmap_len
Quoted 28 lines · Gustavo A. R. Silva
Add sanity checks for both
tlv_lenandtlv_bitmap_lenbefore decoding data fromevent_buf.This prevents any malicious or buggy firmware from overflowing
event_bufthrough large values fortlv_lenandtlv_bitmap_len.Suggested-by Dan Williams <[email protected]>Signed-off-by Gustavo A. R. Silva <[email protected]>---
Changes in v2:
- Fix format specifier: %ld -> %zu
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/- Update warning messages to explicitly mention that TLV size is greater than
tlv_buf_len..../net/wireless/marvell/mwifiex/11n_rxreorder.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +0
-0
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv, · line 928
Quoted 8 lines
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +5
-0@@ -921,6 +921,14 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,while (tlv_buf_left >sizeof (*tlv_rxba)) { tlv_type =le16_to_cpu (tlv_rxba->header.type); tlv_len =le16_to_cpu (tlv_rxba->header.len); +if (size_add (sizeof (tlv_rxba->header), tlv_len) > tlv_buf_left) { +mwifiex_dbg (priv->adapter,WARN , +"TLV size (%zu) overflows event_buf buf_left=%d\n" , +size_add (sizeof (tlv_rxba->header), tlv_len), + tlv_buf_left);
With the suggested change to make this a warning and not dbg:
Thanks!
-Kees
Quoted 24 lines
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +11
-0+return ; + } +if (tlv_type !=TLV_TYPE_RXBA_SYNC ) {mwifiex_dbg (priv->adapter,ERROR ,"Wrong TLV id=0x%x\n" , tlv_type);@@ -929,6 +937,14 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv, tlv_seq_num =le16_to_cpu (tlv_rxba->seq_num); tlv_bitmap_len =le16_to_cpu (tlv_rxba->bitmap_len); +if (size_add (sizeof (*tlv_rxba), tlv_bitmap_len) > tlv_buf_left) { +mwifiex_dbg (priv->adapter,WARN , +"TLV size (%zu) overflows event_buf buf_left=%d\n" , +size_add (sizeof (*tlv_rxba), tlv_bitmap_len), + tlv_buf_left); +return ; + } + mwifiex_dbg(priv->adapter, INFO, "%pM tid=%d seq_num=%d bitmap_len=%d\n", tlv_rxba->mac, tlv_rxba->tid, tlv_seq_num,Signature · 1 line
2.34.1
Signature · 1 line
Kees Cook
Brian Norris
maintainerRe: [PATCH v2 3/3] wifi: mwifiex: Sanity check tlv_len and tlv_bitmap_len
Quoted 7 lines · Kees Cook
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv, · line 928
Quoted 4 lines · Gustavo A. R. Silva
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +4
-0+mwifiex_dbg (priv->adapter,WARN , +"TLV size (%zu) overflows event_buf buf_left=%d\n" , +size_add (sizeof (tlv_rxba->header), tlv_len), + tlv_buf_left);With the suggested change to make this a warning and not dbg:
mwifiex_dbg(..., WARN, ...) *is* a warning, not a debug message. Or at least, that's how it's used throughout this driver, even though it actually yields a dev_info()-level message, regardless of the 'mask' arg:
Re: [PATCH v2 3/3] wifi: mwifiex: Sanity check tlv_len and tlv_bitmap_len
Quoted 7 lines · Brian Norris
Quoted 6 lines · Kees Cook
Quoted 4 lines · Gustavo A. R. Silva
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +4
-0+mwifiex_dbg (priv->adapter,WARN , +"TLV size (%zu) overflows event_buf buf_left=%d\n" , +size_add (sizeof (tlv_rxba->header), tlv_len), + tlv_buf_left);
Quoted 6 lines
Quoted 1 line
With the suggested change to make this a warning and not dbg:
mwifiex_dbg(..., WARN, ...)*is* a warning, not a debug message. Or at least, that's how it's used throughout this driver, even though it actually yields a dev_info()-level message, regardless of the 'mask' arg:
Oh duh. My eyes didn't get any further than "dbg". My bad! Yes, this is good as-is. :) Sorry for the noise!
-Kees
Signature · 1 line
Kees Cook