net/ipv4: Use __DECLARE_FLEX_ARRAY() helper
authorGustavo A. R. Silva <gustavoars@kernel.org>
Wed, 31 Aug 2022 19:12:42 +0000 (14:12 -0500)
committerDavid S. Miller <davem@davemloft.net>
Sat, 3 Sep 2022 08:51:10 +0000 (09:51 +0100)
We now have a cleaner way to keep compatibility with user-space
(a.k.a. not breaking it) when we need to keep in place a one-element
array (for its use in user-space) together with a flexible-array
member (for its use in kernel-space) without making it hard to read
at the source level. This is through the use of the new
__DECLARE_FLEX_ARRAY() helper macro.

The size and memory layout of the structure is preserved after the
changes. See below.

Before changes:

$ pahole -C ip_msfilter net/ipv4/igmp.o
struct ip_msfilter {
union {
struct {
__be32     imsf_multiaddr_aux;   /*     0     4 */
__be32     imsf_interface_aux;   /*     4     4 */
__u32      imsf_fmode_aux;       /*     8     4 */
__u32      imsf_numsrc_aux;      /*    12     4 */
__be32     imsf_slist[1];        /*    16     4 */
};                                       /*     0    20 */
struct {
__be32     imsf_multiaddr;       /*     0     4 */
__be32     imsf_interface;       /*     4     4 */
__u32      imsf_fmode;           /*     8     4 */
__u32      imsf_numsrc;          /*    12     4 */
__be32     imsf_slist_flex[0];   /*    16     0 */
};                                       /*     0    16 */
};                                               /*     0    20 */

/* size: 20, cachelines: 1, members: 1 */
/* last cacheline: 20 bytes */
};

After changes:

$ pahole -C ip_msfilter net/ipv4/igmp.o
struct ip_msfilter {
__be32                     imsf_multiaddr;       /*     0     4 */
__be32                     imsf_interface;       /*     4     4 */
__u32                      imsf_fmode;           /*     8     4 */
__u32                      imsf_numsrc;          /*    12     4 */
union {
__be32             imsf_slist[1];        /*    16     4 */
struct {
struct {
} __empty_imsf_slist_flex;       /*    16     0 */
__be32     imsf_slist_flex[0];   /*    16     0 */
};                                       /*    16     0 */
};                                               /*    16     4 */

/* size: 20, cachelines: 1, members: 5 */
/* last cacheline: 20 bytes */
};

In the past, we had to duplicate the whole original structure within
a union, and update the names of all the members. Now, we just need to
declare the flexible-array member to be used in kernel-space through
the __DECLARE_FLEX_ARRAY() helper together with the one-element array,
within a union. This makes the source code more clean and easier to read.

Link: https://github.com/KSPP/linux/issues/193
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/in.h

index 14168225cecdc74cb7c46b3abd0c1f0bcf874a7a..578daa6f816b6264e8e9001db4e142c97faf8659 100644 (file)
@@ -188,21 +188,13 @@ struct ip_mreq_source {
 };
 
 struct ip_msfilter {
+       __be32          imsf_multiaddr;
+       __be32          imsf_interface;
+       __u32           imsf_fmode;
+       __u32           imsf_numsrc;
        union {
-               struct {
-                       __be32          imsf_multiaddr_aux;
-                       __be32          imsf_interface_aux;
-                       __u32           imsf_fmode_aux;
-                       __u32           imsf_numsrc_aux;
-                       __be32          imsf_slist[1];
-               };
-               struct {
-                       __be32          imsf_multiaddr;
-                       __be32          imsf_interface;
-                       __u32           imsf_fmode;
-                       __u32           imsf_numsrc;
-                       __be32          imsf_slist_flex[];
-               };
+               __be32          imsf_slist[1];
+               __DECLARE_FLEX_ARRAY(__be32, imsf_slist_flex);
        };
 };