Re: [syzbot] linux-next test error: WARNING in set_peer
On Tue, Sep 13, 2022 at 12:51:42PM -0700, syzbot wrote: > memcpy: detected field-spanning write (size 28) of single field > "&endpoint.addr" at drivers/net/wireguard/netlink.c:446 (size 16) This is one way to fix it: diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index 0c0644e762e5..dbbeba216530 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -434,16 +434,16 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs) } if (attrs[WGPEER_A_ENDPOINT]) { - struct sockaddr *addr = nla_data(attrs[WGPEER_A_ENDPOINT]); + struct endpoint *raw = nla_data(attrs[WGPEER_A_ENDPOINT]); size_t len = nla_len(attrs[WGPEER_A_ENDPOINT]); if ((len == sizeof(struct sockaddr_in) && -addr->sa_family == AF_INET) || +raw->addr.sa_family == AF_INET) || (len == sizeof(struct sockaddr_in6) && -addr->sa_family == AF_INET6)) { +raw->addr.sa_family == AF_INET6)) { struct endpoint endpoint = { { { 0 } } }; - memcpy(&endpoint.addr, addr, len); + memcpy(&endpoint.addrs, &raw->addrs, len); wg_socket_set_peer_endpoint(peer, &endpoint); } } diff --git a/drivers/net/wireguard/peer.h b/drivers/net/wireguard/peer.h index 76e4d3128ad4..4fbe7940828b 100644 --- a/drivers/net/wireguard/peer.h +++ b/drivers/net/wireguard/peer.h @@ -19,11 +19,13 @@ struct wg_device; struct endpoint { - union { - struct sockaddr addr; - struct sockaddr_in addr4; - struct sockaddr_in6 addr6; - }; + struct_group(addrs, + union { + struct sockaddr addr; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + }; + ); union { struct { struct in_addr src4; diffoscope shows the bounds check gets updated to the full union size: │ - cmp$0x11,%edx │ + cmp$0x1d,%edx and the field name changes in the warning: $ strings clang/drivers/net/wireguard/netlink.o.after | grep ^field field "&endpoint.addrs" at drivers/net/wireguard/netlink.c:446 -- Kees Cook
[PATCH v2 net-next 1/2] skbuff: Move conditional preprocessor directives out of struct sk_buff
In preparation for using the struct_group() macro in struct sk_buff, move the conditional preprocessor directives out of the region of struct sk_buff that will be enclosed by struct_group(). While GCC and Clang are happy with conditional preprocessor directives here, sparse is not, even under -Wno-directive-within-macro[1], as would be seen under a C=1 build: net/core/filter.c: note: in included file (through include/linux/netlink.h, include/linux/sock_diag.h): ./include/linux/skbuff.h:820:1: warning: directive in macro's argument list ./include/linux/skbuff.h:822:1: warning: directive in macro's argument list ./include/linux/skbuff.h:846:1: warning: directive in macro's argument list ./include/linux/skbuff.h:848:1: warning: directive in macro's argument list Additionally remove empty macro argument definitions and usage. "objdump -d" shows no object code differences. [1] https://www.spinics.net/lists/linux-sparse/msg10857.html Signed-off-by: Kees Cook --- include/linux/skbuff.h | 36 +++- net/core/filter.c | 10 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 686a666d073d..0bce88ac799a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -792,7 +792,7 @@ struct sk_buff { #else #define CLONED_MASK1 #endif -#define CLONED_OFFSET()offsetof(struct sk_buff, __cloned_offset) +#define CLONED_OFFSET offsetof(struct sk_buff, __cloned_offset) /* private: */ __u8__cloned_offset[0]; @@ -815,18 +815,10 @@ struct sk_buff { __u32 headers_start[0]; /* public: */ -/* if you move pkt_type around you also must adapt those constants */ -#ifdef __BIG_ENDIAN_BITFIELD -#define PKT_TYPE_MAX (7 << 5) -#else -#define PKT_TYPE_MAX 7 -#endif -#define PKT_TYPE_OFFSET() offsetof(struct sk_buff, __pkt_type_offset) - /* private: */ __u8__pkt_type_offset[0]; /* public: */ - __u8pkt_type:3; + __u8pkt_type:3; /* see PKT_TYPE_MAX */ __u8ignore_df:1; __u8nf_trace:1; __u8ip_summed:2; @@ -842,16 +834,10 @@ struct sk_buff { __u8encap_hdr_csum:1; __u8csum_valid:1; -#ifdef __BIG_ENDIAN_BITFIELD -#define PKT_VLAN_PRESENT_BIT 7 -#else -#define PKT_VLAN_PRESENT_BIT 0 -#endif -#define PKT_VLAN_PRESENT_OFFSET() offsetof(struct sk_buff, __pkt_vlan_present_offset) /* private: */ __u8__pkt_vlan_present_offset[0]; /* public: */ - __u8vlan_present:1; + __u8vlan_present:1; /* See PKT_VLAN_PRESENT_BIT */ __u8csum_complete_sw:1; __u8csum_level:2; __u8csum_not_inet:1; @@ -950,6 +936,22 @@ struct sk_buff { #endif }; +/* if you move pkt_type around you also must adapt those constants */ +#ifdef __BIG_ENDIAN_BITFIELD +#define PKT_TYPE_MAX (7 << 5) +#else +#define PKT_TYPE_MAX 7 +#endif +#define PKT_TYPE_OFFSEToffsetof(struct sk_buff, __pkt_type_offset) + +/* if you move pkt_vlan_present around you also must adapt these constants */ +#ifdef __BIG_ENDIAN_BITFIELD +#define PKT_VLAN_PRESENT_BIT 7 +#else +#define PKT_VLAN_PRESENT_BIT 0 +#endif +#define PKT_VLAN_PRESENT_OFFSEToffsetof(struct sk_buff, __pkt_vlan_present_offset) + #ifdef __KERNEL__ /* * Handling routines are only of interest to the kernel diff --git a/net/core/filter.c b/net/core/filter.c index e471c9b09670..0bf912a44099 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -301,7 +301,7 @@ static u32 convert_skb_access(int skb_field, int dst_reg, int src_reg, break; case SKF_AD_PKTTYPE: - *insn++ = BPF_LDX_MEM(BPF_B, dst_reg, src_reg, PKT_TYPE_OFFSET()); + *insn++ = BPF_LDX_MEM(BPF_B, dst_reg, src_reg, PKT_TYPE_OFFSET); *insn++ = BPF_ALU32_IMM(BPF_AND, dst_reg, PKT_TYPE_MAX); #ifdef __BIG_ENDIAN_BITFIELD *insn++ = BPF_ALU32_IMM(BPF_RSH, dst_reg, 5); @@ -323,7 +323,7 @@ static u32 convert_skb_access(int skb_field, int dst_reg, int src_reg, offsetof(struct sk_buff, vlan_tci)); break; case SKF_AD_VLAN_TAG_PRESENT: - *insn++ = BPF_LDX_MEM(BPF_B, dst_reg, src_reg, PKT_VLAN_PRESENT_OFFSET()); + *insn++ = BPF_LDX_MEM(BPF_B, dst_reg, src_reg, PKT_VLAN_PRESENT_OFFSET); if (PKT_VLAN_PRESENT_BIT) *insn++ = BPF_ALU32_IMM(BPF_RSH, dst_reg, PKT_VLAN_PRESENT_BIT); if (PKT_VLAN_PRESENT_BIT < 7) @@ -8027,7 +802
[PATCH v2 net-next 2/2] skbuff: Switch structure bounds to struct_group()
In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields. Replace the existing empty member position markers "headers_start" and "headers_end" with a struct_group(). This will allow memcpy() and sizeof() to more easily reason about sizes, and improve readability. "pahole" shows no size nor member offset changes to struct sk_buff. "objdump -d" shows no object code changes (outside of WARNs affected by source line number changes). Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Reviewed-by: Jason A. Donenfeld # drivers/net/wireguard/* Link: https://lore.kernel.org/lkml/20210728035006.GD35706@embeddedor --- drivers/net/wireguard/queueing.h | 4 +--- include/linux/skbuff.h | 10 +++--- net/core/skbuff.c| 14 +- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireguard/queueing.h b/drivers/net/wireguard/queueing.h index 4ef2944a68bc..52da5e963003 100644 --- a/drivers/net/wireguard/queueing.h +++ b/drivers/net/wireguard/queueing.h @@ -79,9 +79,7 @@ static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating) u8 sw_hash = skb->sw_hash; u32 hash = skb->hash; skb_scrub_packet(skb, true); - memset(&skb->headers_start, 0, - offsetof(struct sk_buff, headers_end) - - offsetof(struct sk_buff, headers_start)); + memset(&skb->headers, 0, sizeof(skb->headers)); if (encapsulating) { skb->l4_hash = l4_hash; skb->sw_hash = sw_hash; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 0bce88ac799a..b474e5bd71cf 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -808,12 +808,10 @@ struct sk_buff { __u8active_extensions; #endif - /* fields enclosed in headers_start/headers_end are copied + /* Fields enclosed in headers group are copied * using a single memcpy() in __copy_skb_header() */ - /* private: */ - __u32 headers_start[0]; - /* public: */ + struct_group(headers, /* private: */ __u8__pkt_type_offset[0]; @@ -918,9 +916,7 @@ struct sk_buff { u64 kcov_handle; #endif - /* private: */ - __u32 headers_end[0]; - /* public: */ + ); /* end headers group */ /* These elements must be at the end, see alloc_skb() for details. */ sk_buff_data_t tail; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ba2f38246f07..3a42b2a3a571 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -992,12 +992,10 @@ void napi_consume_skb(struct sk_buff *skb, int budget) } EXPORT_SYMBOL(napi_consume_skb); -/* Make sure a field is enclosed inside headers_start/headers_end section */ +/* Make sure a field is contained by headers group */ #define CHECK_SKB_FIELD(field) \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) < \ -offsetof(struct sk_buff, headers_start)); \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) > \ -offsetof(struct sk_buff, headers_end));\ + BUILD_BUG_ON(offsetof(struct sk_buff, field) != \ +offsetof(struct sk_buff, headers.field)); \ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) { @@ -1009,14 +1007,12 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) __skb_ext_copy(new, old); __nf_copy(new, old, false); - /* Note : this field could be in headers_start/headers_end section + /* Note : this field could be in the headers group. * It is not yet because we do not want to have a 16 bit hole */ new->queue_mapping = old->queue_mapping; - memcpy(&new->headers_start, &old->headers_start, - offsetof(struct sk_buff, headers_end) - - offsetof(struct sk_buff, headers_start)); + memcpy(&new->headers, &old->headers, sizeof(new->headers)); CHECK_SKB_FIELD(protocol); CHECK_SKB_FIELD(csum); CHECK_SKB_FIELD(hash); -- 2.30.2
[PATCH v2 net-next 0/2] skbuff: Switch structure bounds to struct_group()
Hi, This is a pair of patches to add struct_group() to struct sk_buff. The first is needed to work around sparse-specific complaints, and is new for v2. The second patch is the same as originally sent as v1. -Kees Kees Cook (2): skbuff: Move conditional preprocessor directives out of struct sk_buff skbuff: Switch structure bounds to struct_group() drivers/net/wireguard/queueing.h | 4 +-- include/linux/skbuff.h | 46 +++- net/core/filter.c| 10 +++ net/core/skbuff.c| 14 -- 4 files changed, 33 insertions(+), 41 deletions(-) -- 2.30.2
Re: [PATCH] skbuff: Switch structure bounds to struct_group()
On Fri, Nov 19, 2021 at 10:53:05AM -0800, Jakub Kicinski wrote: > On Fri, 19 Nov 2021 10:41:44 -0800 Jakub Kicinski wrote: > > On Fri, 19 Nov 2021 10:26:19 -0800 Kees Cook wrote: > > > On Thu, Nov 18, 2021 at 11:13:55PM -0800, Jakub Kicinski wrote: > > > > This adds ~27k of these warnings to W=1 gcc builds: > > > > > > > > include/linux/skbuff.h:851:1: warning: directive in macro's argument > > > > list > > > > > > Hrm, I can't reproduce this, using several GCC versions and net-next. What > > > compiler version[1] and base commit[2] were used here? > > > > gcc version 11.2.1 20210728 (Red Hat 11.2.1-1) (GCC) > > > > HEAD was at: 3b1abcf12894 Merge tag 'regmap-no-bus-update-bits' of git://... > > Ah, damn, I just realized, it's probably sparse! The build sets C=1. *head desk* I looked right at the "C=1" (noting it was missing for the clang build) and didn't put it together. Let me see what I need to do to make sparse happy... -- Kees Cook
Re: [PATCH] skbuff: Switch structure bounds to struct_group()
On Thu, Nov 18, 2021 at 11:13:55PM -0800, Jakub Kicinski wrote: > On Thu, 18 Nov 2021 10:36:15 -0800 Kees Cook wrote: > > In preparation for FORTIFY_SOURCE performing compile-time and run-time > > field bounds checking for memcpy(), memmove(), and memset(), avoid > > intentionally writing across neighboring fields. > > > > Replace the existing empty member position markers "headers_start" and > > "headers_end" with a struct_group(). This will allow memcpy() and sizeof() > > to more easily reason about sizes, and improve readability. > > > > "pahole" shows no size nor member offset changes to struct sk_buff. > > "objdump -d" shows no object code changes (outside of WARNs affected by > > source line number changes). > > This adds ~27k of these warnings to W=1 gcc builds: > > include/linux/skbuff.h:851:1: warning: directive in macro's argument list Hrm, I can't reproduce this, using several GCC versions and net-next. What compiler version[1] and base commit[2] were used here? -Kees [1] https://github.com/kuba-moo/nipa/pull/10 [2] https://github.com/kuba-moo/nipa/pull/11 -- Kees Cook
Re: [PATCH] skbuff: Switch structure bounds to struct_group()
On Thu, Nov 18, 2021 at 11:13:55PM -0800, Jakub Kicinski wrote: > On Thu, 18 Nov 2021 10:36:15 -0800 Kees Cook wrote: > > In preparation for FORTIFY_SOURCE performing compile-time and run-time > > field bounds checking for memcpy(), memmove(), and memset(), avoid > > intentionally writing across neighboring fields. > > > > Replace the existing empty member position markers "headers_start" and > > "headers_end" with a struct_group(). This will allow memcpy() and sizeof() > > to more easily reason about sizes, and improve readability. > > > > "pahole" shows no size nor member offset changes to struct sk_buff. > > "objdump -d" shows no object code changes (outside of WARNs affected by > > source line number changes). > > This adds ~27k of these warnings to W=1 gcc builds: > > include/linux/skbuff.h:851:1: warning: directive in macro's argument list Oh my, I see it[1]. I will get that fixed. This smells like a missing header or something weird. I have a dim memory of fixing this warning long ago when evolving this series. Thanks! -Kees [1] https://patchwork.kernel.org/project/netdevbpf/patch/2028183615.1281978-1-keesc...@chromium.org/ -- Kees Cook
[PATCH] skbuff: Switch structure bounds to struct_group()
In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields. Replace the existing empty member position markers "headers_start" and "headers_end" with a struct_group(). This will allow memcpy() and sizeof() to more easily reason about sizes, and improve readability. "pahole" shows no size nor member offset changes to struct sk_buff. "objdump -d" shows no object code changes (outside of WARNs affected by source line number changes). Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Reviewed-by: Jason A. Donenfeld # drivers/net/wireguard/* --- drivers/net/wireguard/queueing.h | 4 +--- include/linux/skbuff.h | 10 +++--- net/core/skbuff.c| 14 +- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireguard/queueing.h b/drivers/net/wireguard/queueing.h index 4ef2944a68bc..52da5e963003 100644 --- a/drivers/net/wireguard/queueing.h +++ b/drivers/net/wireguard/queueing.h @@ -79,9 +79,7 @@ static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating) u8 sw_hash = skb->sw_hash; u32 hash = skb->hash; skb_scrub_packet(skb, true); - memset(&skb->headers_start, 0, - offsetof(struct sk_buff, headers_end) - - offsetof(struct sk_buff, headers_start)); + memset(&skb->headers, 0, sizeof(skb->headers)); if (encapsulating) { skb->l4_hash = l4_hash; skb->sw_hash = sw_hash; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 686a666d073d..875adfd056b6 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -808,12 +808,10 @@ struct sk_buff { __u8active_extensions; #endif - /* fields enclosed in headers_start/headers_end are copied + /* Fields enclosed in headers group are copied * using a single memcpy() in __copy_skb_header() */ - /* private: */ - __u32 headers_start[0]; - /* public: */ + struct_group(headers, /* if you move pkt_type around you also must adapt those constants */ #ifdef __BIG_ENDIAN_BITFIELD @@ -932,9 +930,7 @@ struct sk_buff { u64 kcov_handle; #endif - /* private: */ - __u32 headers_end[0]; - /* public: */ + ); /* end headers group */ /* These elements must be at the end, see alloc_skb() for details. */ sk_buff_data_t tail; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ba2f38246f07..3a42b2a3a571 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -992,12 +992,10 @@ void napi_consume_skb(struct sk_buff *skb, int budget) } EXPORT_SYMBOL(napi_consume_skb); -/* Make sure a field is enclosed inside headers_start/headers_end section */ +/* Make sure a field is contained by headers group */ #define CHECK_SKB_FIELD(field) \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) < \ -offsetof(struct sk_buff, headers_start)); \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) > \ -offsetof(struct sk_buff, headers_end));\ + BUILD_BUG_ON(offsetof(struct sk_buff, field) != \ +offsetof(struct sk_buff, headers.field)); \ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) { @@ -1009,14 +1007,12 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) __skb_ext_copy(new, old); __nf_copy(new, old, false); - /* Note : this field could be in headers_start/headers_end section + /* Note : this field could be in the headers group. * It is not yet because we do not want to have a 16 bit hole */ new->queue_mapping = old->queue_mapping; - memcpy(&new->headers_start, &old->headers_start, - offsetof(struct sk_buff, headers_end) - - offsetof(struct sk_buff, headers_start)); + memcpy(&new->headers, &old->headers, sizeof(new->headers)); CHECK_SKB_FIELD(protocol); CHECK_SKB_FIELD(csum); CHECK_SKB_FIELD(hash); -- 2.30.2
[PATCH v2 07/63] skbuff: Switch structure bounds to struct_group()
In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields. Replace the existing empty member position markers "headers_start" and "headers_end" with a struct_group(). This will allow memcpy() and sizeof() to more easily reason about sizes, and improve readability. "pahole" shows no size nor member offset changes to struct sk_buff. "objdump -d" shows no object code changes (outside of WARNs affected by source line number changes). Cc: "Jason A. Donenfeld" Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Jonathan Lemon Cc: Alexander Lobakin Cc: Jakub Sitnicki Cc: Marco Elver Cc: Willem de Bruijn Cc: wireguard@lists.zx2c4.com Cc: net...@vger.kernel.org Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/lkml/20210728035006.GD35706@embeddedor --- drivers/net/wireguard/queueing.h | 4 +--- include/linux/skbuff.h | 9 - net/core/skbuff.c| 14 +- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireguard/queueing.h b/drivers/net/wireguard/queueing.h index 4ef2944a68bc..52da5e963003 100644 --- a/drivers/net/wireguard/queueing.h +++ b/drivers/net/wireguard/queueing.h @@ -79,9 +79,7 @@ static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating) u8 sw_hash = skb->sw_hash; u32 hash = skb->hash; skb_scrub_packet(skb, true); - memset(&skb->headers_start, 0, - offsetof(struct sk_buff, headers_end) - - offsetof(struct sk_buff, headers_start)); + memset(&skb->headers, 0, sizeof(skb->headers)); if (encapsulating) { skb->l4_hash = l4_hash; skb->sw_hash = sw_hash; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6bdb0db3e825..fee9041aa402 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -801,11 +801,10 @@ struct sk_buff { __u8active_extensions; #endif - /* fields enclosed in headers_start/headers_end are copied + /* Fields enclosed in headers group are copied * using a single memcpy() in __copy_skb_header() */ - /* private: */ - __u32 headers_start[0]; + struct_group(headers, /* public: */ /* if you move pkt_type around you also must adapt those constants */ @@ -922,8 +921,8 @@ struct sk_buff { u64 kcov_handle; #endif - /* private: */ - __u32 headers_end[0]; + ); /* end headers group */ + /* public: */ /* These elements must be at the end, see alloc_skb() for details. */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f9311762cc47..fd5ce57ccce6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -991,12 +991,10 @@ void napi_consume_skb(struct sk_buff *skb, int budget) } EXPORT_SYMBOL(napi_consume_skb); -/* Make sure a field is enclosed inside headers_start/headers_end section */ +/* Make sure a field is contained by headers group */ #define CHECK_SKB_FIELD(field) \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) < \ -offsetof(struct sk_buff, headers_start)); \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) > \ -offsetof(struct sk_buff, headers_end));\ + BUILD_BUG_ON(offsetof(struct sk_buff, field) != \ +offsetof(struct sk_buff, headers.field)); \ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) { @@ -1008,14 +1006,12 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) __skb_ext_copy(new, old); __nf_copy(new, old, false); - /* Note : this field could be in headers_start/headers_end section + /* Note : this field could be in the headers group. * It is not yet because we do not want to have a 16 bit hole */ new->queue_mapping = old->queue_mapping; - memcpy(&new->headers_start, &old->headers_start, - offsetof(struct sk_buff, headers_end) - - offsetof(struct sk_buff, headers_start)); + memcpy(&new->headers, &old->headers, sizeof(new->headers)); CHECK_SKB_FIELD(protocol); CHECK_SKB_FIELD(csum); CHECK_SKB_FIELD(hash); -- 2.30.2