-Wflex-array-member-not-at-end was introduced in GCC-14, and we are
getting ready to enable it, globally.

Move the conflicting declarations (which in a couple of cases happen
to be in a union, so the entire unions are moved) to the end of the
corresponding structures. Notice that `struct il_tx_beacon_cmd`,
`struct il4965_tx_resp`, and `struct il3945_tx_beacon_cmd` are flexible
structures, this is structures that contain a flexible-array member.

The case for struct il4965_beacon_notif is different. Since this
structure is defined by hardware, we use the struct_group() helper
to create the new `struct il4965_tx_resp_hdr` type. We then use this newly
created type to replace the obhect type of  causing trouble in
struct il4965_beacon_notif, namely `stryct il4965_tx_resp`.

In order to preserve the memory layout in struct il4965_beacon_notif,
add member `__le32 beacon_tx_status`, which was previously included
by `struct il4965_tx_resp` (as `__le32 status`), but it's not present
in the newly created type `struct il4965_tx_resp_hdr`.

Notice that after this changes, the size of struct il4965_beacon_notif
along with its member's offsets remain the same, hence the memory
layout doesn't change:

Before changes:
struct il4965_beacon_notif {
        struct il4965_tx_resp      beacon_notify_hdr;    /*     0    24 */
        __le32                     low_tsf;              /*    24     4 */
        __le32                     high_tsf;             /*    28     4 */
        __le32                     ibss_mgr_status;      /*    32     4 */

        /* size: 36, cachelines: 1, members: 4 */
        /* last cacheline: 36 bytes */
};

After changes:
struct il4965_beacon_notif {
        struct il4965_tx_resp_hdr  beacon_notify_hdr;    /*     0    20 */
        __le32                     beacon_tx_status;     /*    20     4 */
        __le32                     low_tsf;              /*    24     4 */
        __le32                     high_tsf;             /*    28     4 */
        __le32                     ibss_mgr_status;      /*    32     4 */

        /* size: 36, cachelines: 1, members: 5 */
        /* last cacheline: 36 bytes */
};

We also want to ensure that when new members are added to the flexible
structure `struct il4965_tx_resp` (if any), they are always included
within the newly created struct type. To enforce this, we use
`static_assert()` (which is intentionally placed right after the struct,
this is, no blank line in between). This ensures that the memory layout
of both the flexible structure and the new `struct il4965_tx_resp_hdr`
type remains consistent after any changes.

Lastly, refactor the rest of the code, accordingly.

With these changes fix the following warnings:

11 drivers/net/wireless/intel/iwlegacy/common.h:526:11: warning: structure 
containing a flexible array member is not at the end of another structure 
[-Wflex-array-member-not-at-end]
11 drivers/net/wireless/intel/iwlegacy/commands.h:2667:31: warning: structure 
containing a flexible array member is not at the end of another structure 
[-Wflex-array-member-not-at-end]
4 drivers/net/wireless/intel/iwlegacy/3945.h:131:11: warning: structure 
containing a flexible array member is not at the end of another structure 
[-Wflex-array-member-not-at-end]

Signed-off-by: Gustavo A. R. Silva <[email protected]>
---
Changes in v2:
 - Use the struct_group() helper, and update the conflicting type
   (struct il4965_tx_resp -> struct il4965_tx_resp_hdr) in
   struct il4965_beacon_notif.

v1:
 - Link: https://lore.kernel.org/linux-hardening/aR2CtqZI3atH0HmE@kspp/

 drivers/net/wireless/intel/iwlegacy/3945.h    |  4 +-
 .../net/wireless/intel/iwlegacy/4965-mac.c    |  2 +-
 .../net/wireless/intel/iwlegacy/commands.h    | 41 +++++++++++--------
 drivers/net/wireless/intel/iwlegacy/common.h  |  4 +-
 4 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlegacy/3945.h 
b/drivers/net/wireless/intel/iwlegacy/3945.h
index fb1e33c89d0e..ed63b31fee9a 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945.h
+++ b/drivers/net/wireless/intel/iwlegacy/3945.h
@@ -123,13 +123,15 @@ enum il3945_antenna {
 #define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
 
 struct il3945_frame {
+       struct list_head list;
+
+       /* Must be last as it ends in a flexible-array member. */
        union {
                struct ieee80211_hdr frame;
                struct il3945_tx_beacon_cmd beacon;
                u8 raw[IEEE80211_FRAME_LEN];
                u8 cmd[360];
        } u;
-       struct list_head list;
 };
 
 #define SUP_RATE_11A_MAX_NUM_CHANNELS  8
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c 
b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
index 57fa866efd9f..f5a99a2ee95a 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
@@ -4076,7 +4076,7 @@ il4965_hdl_beacon(struct il_priv *il, struct il_rx_buf 
*rxb)
        u8 rate = il4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
 
        D_RX("beacon status %x retries %d iss %d tsf:0x%.8x%.8x rate %d\n",
-            le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK,
+            le32_to_cpu(beacon->beacon_tx_status) & TX_STATUS_MSK,
             beacon->beacon_notify_hdr.failure_frame,
             le32_to_cpu(beacon->ibss_mgr_status),
             le32_to_cpu(beacon->high_tsf), le32_to_cpu(beacon->low_tsf), rate);
diff --git a/drivers/net/wireless/intel/iwlegacy/commands.h 
b/drivers/net/wireless/intel/iwlegacy/commands.h
index b61b8f377702..630bc12cd0d5 100644
--- a/drivers/net/wireless/intel/iwlegacy/commands.h
+++ b/drivers/net/wireless/intel/iwlegacy/commands.h
@@ -1691,22 +1691,25 @@ struct agg_tx_status {
 } __packed;
 
 struct il4965_tx_resp {
-       u8 frame_count;         /* 1 no aggregation, >1 aggregation */
-       u8 bt_kill_count;       /* # blocked by bluetooth (unused for agg) */
-       u8 failure_rts;         /* # failures due to unsuccessful RTS */
-       u8 failure_frame;       /* # failures due to no ACK (unused for agg) */
-
-       /* For non-agg:  Rate at which frame was successful.
-        * For agg:  Rate at which all frames were transmitted. */
-       __le32 rate_n_flags;    /* RATE_MCS_*  */
-
-       /* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
-        * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
-       __le16 wireless_media_time;     /* uSecs */
-
-       __le16 reserved;
-       __le32 pa_power1;       /* RF power amplifier measurement (not used) */
-       __le32 pa_power2;
+       /* New members MUST be added within the __struct_group() macro below. */
+       __struct_group(il4965_tx_resp_hdr, __hdr, __packed,
+               u8 frame_count;         /* 1 no aggregation, >1 aggregation */
+               u8 bt_kill_count;       /* # blocked by bluetooth (unused for 
agg) */
+               u8 failure_rts;         /* # failures due to unsuccessful RTS */
+               u8 failure_frame;       /* # failures due to no ACK (unused for 
agg) */
+
+               /* For non-agg:  Rate at which frame was successful.
+                * For agg:  Rate at which all frames were transmitted. */
+               __le32 rate_n_flags;    /* RATE_MCS_*  */
+
+               /* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
+                * For agg:  RTS + CTS + aggregation tx time + block-ack time. 
*/
+               __le16 wireless_media_time;     /* uSecs */
+
+               __le16 reserved;
+               __le32 pa_power1;       /* RF power amplifier measurement (not 
used) */
+               __le32 pa_power2;
+       );
 
        /*
         * For non-agg:  frame status TX_STATUS_*
@@ -1726,6 +1729,9 @@ struct il4965_tx_resp {
                DECLARE_FLEX_ARRAY(struct agg_tx_status, agg_status);   /* for 
each agg frame */
        } u;
 } __packed;
+static_assert(offsetof(struct il4965_tx_resp, u.agg_status) ==
+             sizeof(struct il4965_tx_resp_hdr),
+             "struct member likely outside of __struct_group()");
 
 /*
  * N_COMPRESSED_BA = 0xc5 (response only, not a command)
@@ -2664,7 +2670,8 @@ struct il3945_beacon_notif {
 } __packed;
 
 struct il4965_beacon_notif {
-       struct il4965_tx_resp beacon_notify_hdr;
+       struct il4965_tx_resp_hdr beacon_notify_hdr;
+       __le32 beacon_tx_status;
        __le32 low_tsf;
        __le32 high_tsf;
        __le32 ibss_mgr_status;
diff --git a/drivers/net/wireless/intel/iwlegacy/common.h 
b/drivers/net/wireless/intel/iwlegacy/common.h
index 4c9836ab11dd..21f1c7702add 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.h
+++ b/drivers/net/wireless/intel/iwlegacy/common.h
@@ -518,13 +518,15 @@ struct il_channel_info {
 #define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
 
 struct il_frame {
+       struct list_head list;
+
+       /* Must be last as it ends in a flexible-array member. */
        union {
                struct ieee80211_hdr frame;
                struct il_tx_beacon_cmd beacon;
                u8 raw[IEEE80211_FRAME_LEN];
                u8 cmd[360];
        } u;
-       struct list_head list;
 };
 
 enum {
-- 
2.43.0


Reply via email to