On Thu, 7 Nov 2024 at 16:32, Peter Maydell <peter.mayd...@linaro.org> wrote: > > In virtio-net.c we assume that the IP length field in the packet is > aligned, and we copy its address into a uint16_t* in the > VirtioNetRscUnit struct which we then dereference later. This isn't > a safe assumption; it will also result in compilation failures if we > mark the ip_header struct as QEMU_PACKED because the compiler will > not let you take the address of an unaligned struct field. > > Make the ip_plen field in VirtioNetRscUnit a void*, and make all the > places where we read or write through that pointer instead use some > new accessor functions read_unit_ip_len() and write_unit_ip_len() > which account for the pointer being potentially unaligned and also do > the network-byte-order conversion we were previously using htons() to > perform. > > Signed-off-by: Peter Maydell <peter.mayd...@linaro.org> > --- > include/hw/virtio/virtio-net.h | 2 +- > hw/net/virtio-net.c | 23 +++++++++++++++++++---- > 2 files changed, 20 insertions(+), 5 deletions(-) > > diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h > index 060c23c04d2..b9ea9e824e3 100644 > --- a/include/hw/virtio/virtio-net.h > +++ b/include/hw/virtio/virtio-net.h > @@ -102,7 +102,7 @@ typedef struct VirtioNetRscStat { > /* Rsc unit general info used to checking if can coalescing */ > typedef struct VirtioNetRscUnit { > void *ip; /* ip header */ > - uint16_t *ip_plen; /* data len pointer in ip header field */ > + void *ip_plen; /* pointer to unaligned uint16_t data len in ip header */ > struct tcp_header *tcp; /* tcp header */ > uint16_t tcp_hdrlen; /* tcp header len */ > uint16_t payload; /* pure payload without virtio/eth/ip/tcp */ > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c > index f2104ed364a..11cf462180d 100644 > --- a/hw/net/virtio-net.c > +++ b/hw/net/virtio-net.c > @@ -2049,6 +2049,21 @@ static ssize_t virtio_net_do_receive(NetClientState > *nc, const uint8_t *buf, > return virtio_net_receive_rcu(nc, buf, size, false); > } > > +/* > + * Accessors to read and write the IP packet data length field. This > + * is a potentially unaligned network-byte-order 16 bit unsigned integer > + * pointed to by unit->ip_len. > + */ > +static uint16_t read_unit_ip_len(VirtioNetRscUnit *unit) > +{ > + return ldl_be_p(unit->ip_plen); > +} > + > +static void write_unit_ip_len(VirtioNetRscUnit *unit, uint16_t l) > +{ > + stl_be_p(unit->ip_plen, l); > +}
These should of course be lduw_be_p() and stw_be_p(), since it's a 16 bit field. Interestingly nothing fails in "make check" or "make check-functional" if this breaks, suggesting we aren't exercising virtio-net very hard. -- PMM