]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
virtio_net: Fix misalignment bug in struct virtnet_info
authorGustavo A. R. Silva <gustavoars@kernel.org>
Sat, 10 Jan 2026 08:07:17 +0000 (17:07 +0900)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 15 Jan 2026 09:18:42 +0000 (10:18 +0100)
Use the new TRAILING_OVERLAP() helper to fix a misalignment bug
along with the following warning:

drivers/net/virtio_net.c:429:46: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

This helper creates a union between a flexible-array member (FAM)
and a set of members that would otherwise follow it (in this case
`u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];`). This
overlays the trailing members (rss_hash_key_data) onto the FAM
(hash_key_data) while keeping the FAM and the start of MEMBERS aligned.
The static_assert() ensures this alignment remains.

Notice that due to tail padding in flexible `struct
virtio_net_rss_config_trailer`, `rss_trailer.hash_key_data`
(at offset 83 in struct virtnet_info) and `rss_hash_key_data` (at
offset 84 in struct virtnet_info) are misaligned by one byte. See
below:

struct virtio_net_rss_config_trailer {
        __le16                     max_tx_vq;            /*     0     2 */
        __u8                       hash_key_length;      /*     2     1 */
        __u8                       hash_key_data[];      /*     3     0 */

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

struct virtnet_info {
...
        struct virtio_net_rss_config_trailer rss_trailer; /*    80     4 */

        /* XXX last struct has 1 byte of padding */

        u8                         rss_hash_key_data[40]; /*    84    40 */
...
        /* size: 832, cachelines: 13, members: 48 */
        /* sum members: 801, holes: 8, sum holes: 31 */
        /* paddings: 2, sum paddings: 5 */
};

After changes, those members are correctly aligned at offset 795:

struct virtnet_info {
...
        union {
                struct virtio_net_rss_config_trailer rss_trailer; /*   792     4 */
                struct {
                        unsigned char __offset_to_hash_key_data[3]; /*   792     3 */
                        u8         rss_hash_key_data[40]; /*   795    40 */
                };                                       /*   792    43 */
        };                                               /*   792    44 */
...
        /* size: 840, cachelines: 14, members: 47 */
        /* sum members: 801, holes: 8, sum holes: 35 */
        /* padding: 4 */
        /* paddings: 1, sum paddings: 4 */
        /* last cacheline: 8 bytes */
};

As a result, the RSS key passed to the device is shifted by 1
byte: the last byte is cut off, and instead a (possibly
uninitialized) byte is added at the beginning.

As a last note `struct virtio_net_rss_config_hdr *rss_hdr;` is also
moved to the end, since it seems those three members should stick
around together. :)

Cc: stable@vger.kernel.org
Fixes: ed3100e90d0d ("virtio_net: Use new RSS config structs")
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Link: https://patch.msgid.link/aWIItWq5dV9XTTCJ@kspp
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/virtio_net.c

index ca92b4a1879cef61340da038054d7acefa87efb4..db88dcaefb20b18925bfbf6374bc7a0439970722 100644 (file)
@@ -425,9 +425,6 @@ struct virtnet_info {
        u16 rss_indir_table_size;
        u32 rss_hash_types_supported;
        u32 rss_hash_types_saved;
-       struct virtio_net_rss_config_hdr *rss_hdr;
-       struct virtio_net_rss_config_trailer rss_trailer;
-       u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];
 
        /* Has control virtqueue */
        bool has_cvq;
@@ -484,7 +481,16 @@ struct virtnet_info {
        struct failover *failover;
 
        u64 device_stats_cap;
+
+       struct virtio_net_rss_config_hdr *rss_hdr;
+
+       /* Must be last as it ends in a flexible-array member. */
+       TRAILING_OVERLAP(struct virtio_net_rss_config_trailer, rss_trailer, hash_key_data,
+               u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+       );
 };
+static_assert(offsetof(struct virtnet_info, rss_trailer.hash_key_data) ==
+             offsetof(struct virtnet_info, rss_hash_key_data));
 
 struct padded_vnet_hdr {
        struct virtio_net_hdr_v1_hash hdr;