mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
virtio_net: Fix misalignment bug in struct virtnet_info
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: ed3100e90d ("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>
This commit is contained in:
committed by
Paolo Abeni
parent
3879cffd9d
commit
4156c3745f
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user