mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-16 07:35:14 +00:00
gro: ensure frag0 meets IP header alignment
commit38ec4944b5
upstream. After commit0f6925b3e8
("virtio_net: Do not pull payload in skb->head") Guenter Roeck reported one failure in his tests using sh architecture. After much debugging, we have been able to spot silent unaligned accesses in inet_gro_receive() The issue at hand is that upper networking stacks assume their header is word-aligned. Low level drivers are supposed to reserve NET_IP_ALIGN bytes before the Ethernet header to make that happen. This patch hardens skb_gro_reset_offset() to not allow frag0 fast-path if the fragment is not properly aligned. Some arches like x86, arm64 and powerpc do not care and define NET_IP_ALIGN as 0, this extra check will be a NOP for them. Note that if frag0 is not used, GRO will call pskb_may_pull() as many times as needed to pull network and transport headers. Fixes:0f6925b3e8
("virtio_net: Do not pull payload in skb->head") Fixes:78a478d0ef
("gro: Inline skb_gro_header and cache frag0 virtual address") Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Guenter Roeck <linux@roeck-us.net> Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Cc: "Michael S. Tsirkin" <mst@redhat.com> Cc: Jason Wang <jasowang@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Tested-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
16851e34b6
commit
d94d95ae0d
2 changed files with 11 additions and 1 deletions
|
@ -2788,6 +2788,15 @@ static inline void skb_propagate_pfmemalloc(struct page *page,
|
|||
skb->pfmemalloc = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_frag_off() - Returns the offset of a skb fragment
|
||||
* @frag: the paged fragment
|
||||
*/
|
||||
static inline unsigned int skb_frag_off(const skb_frag_t *frag)
|
||||
{
|
||||
return frag->page_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_frag_page - retrieve the page referred to by a paged fragment
|
||||
* @frag: the paged fragment
|
||||
|
|
|
@ -5400,7 +5400,8 @@ static void skb_gro_reset_offset(struct sk_buff *skb)
|
|||
|
||||
if (skb_mac_header(skb) == skb_tail_pointer(skb) &&
|
||||
pinfo->nr_frags &&
|
||||
!PageHighMem(skb_frag_page(frag0))) {
|
||||
!PageHighMem(skb_frag_page(frag0)) &&
|
||||
(!NET_IP_ALIGN || !(skb_frag_off(frag0) & 3))) {
|
||||
NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
|
||||
NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int,
|
||||
skb_frag_size(frag0),
|
||||
|
|
Loading…
Reference in a new issue