Re: [syzbot] linux-next test error: WARNING in set_peer

2022-09-13 Thread Kees Cook
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

2021-11-20 Thread Kees Cook
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()

2021-11-20 Thread Kees Cook
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()

2021-11-20 Thread Kees Cook
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()

2021-11-19 Thread Kees Cook
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()

2021-11-19 Thread Kees Cook
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()

2021-11-19 Thread Kees Cook
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()

2021-11-18 Thread Kees Cook
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()

2021-08-17 Thread Kees Cook
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