Skip to content

Commit db243b7

Browse files
GustavoARSilvadavem330
authored andcommitted
net/ipv4/ipv6: Replace one-element arraya with flexible-array members
There is a regular need in the kernel to provide a way to declare having a dynamically sized set of trailing elements in a structure. Kernel code should always use “flexible array members”[1] for these cases. The older style of one-element or zero-length arrays should no longer be used[2]. Use an anonymous union with a couple of anonymous structs in order to keep userspace unchanged and refactor the related code accordingly: $ pahole -C group_filter net/ipv4/ip_sockglue.o struct group_filter { union { struct { __u32 gf_interface_aux; /* 0 4 */ /* XXX 4 bytes hole, try to pack */ struct __kernel_sockaddr_storage gf_group_aux; /* 8 128 */ /* --- cacheline 2 boundary (128 bytes) was 8 bytes ago --- */ __u32 gf_fmode_aux; /* 136 4 */ __u32 gf_numsrc_aux; /* 140 4 */ struct __kernel_sockaddr_storage gf_slist[1]; /* 144 128 */ }; /* 0 272 */ struct { __u32 gf_interface; /* 0 4 */ /* XXX 4 bytes hole, try to pack */ struct __kernel_sockaddr_storage gf_group; /* 8 128 */ /* --- cacheline 2 boundary (128 bytes) was 8 bytes ago --- */ __u32 gf_fmode; /* 136 4 */ __u32 gf_numsrc; /* 140 4 */ struct __kernel_sockaddr_storage gf_slist_flex[0]; /* 144 0 */ }; /* 0 144 */ }; /* 0 272 */ /* size: 272, cachelines: 5, members: 1 */ /* last cacheline: 16 bytes */ }; $ pahole -C compat_group_filter net/ipv4/ip_sockglue.o struct compat_group_filter { union { struct { __u32 gf_interface_aux; /* 0 4 */ struct __kernel_sockaddr_storage gf_group_aux __attribute__((__aligned__(4))); /* 4 128 */ /* --- cacheline 2 boundary (128 bytes) was 4 bytes ago --- */ __u32 gf_fmode_aux; /* 132 4 */ __u32 gf_numsrc_aux; /* 136 4 */ struct __kernel_sockaddr_storage gf_slist[1] __attribute__((__aligned__(4))); /* 140 128 */ } __attribute__((__packed__)) __attribute__((__aligned__(4))); /* 0 268 */ struct { __u32 gf_interface; /* 0 4 */ struct __kernel_sockaddr_storage gf_group __attribute__((__aligned__(4))); /* 4 128 */ /* --- cacheline 2 boundary (128 bytes) was 4 bytes ago --- */ __u32 gf_fmode; /* 132 4 */ __u32 gf_numsrc; /* 136 4 */ struct __kernel_sockaddr_storage gf_slist_flex[0] __attribute__((__aligned__(4))); /* 140 0 */ } __attribute__((__packed__)) __attribute__((__aligned__(4))); /* 0 140 */ } __attribute__((__aligned__(1))); /* 0 268 */ /* size: 268, cachelines: 5, members: 1 */ /* forced alignments: 1 */ /* last cacheline: 12 bytes */ } __attribute__((__packed__)); This helps with the ongoing efforts to globally enable -Warray-bounds and get us closer to being able to tighten the FORTIFY_SOURCE routines on memcpy(). [1] https://en.wikipedia.org/wiki/Flexible_array_member [2] https://www.kernel.org/doc/html/v5.10/process/deprecated.html#zero-length-and-one-element-arrays Link: KSPP/linux#79 Link: KSPP/linux#109 Signed-off-by: Gustavo A. R. Silva <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d15040a commit db243b7

File tree

4 files changed

+55
-30
lines changed

4 files changed

+55
-30
lines changed

include/net/compat.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,26 @@ struct compat_group_source_req {
7171
} __packed;
7272

7373
struct compat_group_filter {
74-
__u32 gf_interface;
75-
struct __kernel_sockaddr_storage gf_group
76-
__aligned(4);
77-
__u32 gf_fmode;
78-
__u32 gf_numsrc;
79-
struct __kernel_sockaddr_storage gf_slist[1]
80-
__aligned(4);
74+
union {
75+
struct {
76+
__u32 gf_interface_aux;
77+
struct __kernel_sockaddr_storage gf_group_aux
78+
__aligned(4);
79+
__u32 gf_fmode_aux;
80+
__u32 gf_numsrc_aux;
81+
struct __kernel_sockaddr_storage gf_slist[1]
82+
__aligned(4);
83+
} __packed;
84+
struct {
85+
__u32 gf_interface;
86+
struct __kernel_sockaddr_storage gf_group
87+
__aligned(4);
88+
__u32 gf_fmode;
89+
__u32 gf_numsrc;
90+
struct __kernel_sockaddr_storage gf_slist_flex[]
91+
__aligned(4);
92+
} __packed;
93+
};
8194
} __packed;
8295

8396
#endif /* NET_COMPAT_H */

include/uapi/linux/in.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,22 @@ struct group_source_req {
222222
};
223223

224224
struct group_filter {
225-
__u32 gf_interface; /* interface index */
226-
struct __kernel_sockaddr_storage gf_group; /* multicast address */
227-
__u32 gf_fmode; /* filter mode */
228-
__u32 gf_numsrc; /* number of sources */
229-
struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
225+
union {
226+
struct {
227+
__u32 gf_interface_aux; /* interface index */
228+
struct __kernel_sockaddr_storage gf_group_aux; /* multicast address */
229+
__u32 gf_fmode_aux; /* filter mode */
230+
__u32 gf_numsrc_aux; /* number of sources */
231+
struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
232+
};
233+
struct {
234+
__u32 gf_interface; /* interface index */
235+
struct __kernel_sockaddr_storage gf_group; /* multicast address */
236+
__u32 gf_fmode; /* filter mode */
237+
__u32 gf_numsrc; /* number of sources */
238+
struct __kernel_sockaddr_storage gf_slist_flex[]; /* interface index */
239+
};
240+
};
230241
};
231242

232243
#define GROUP_FILTER_SIZE(numsrc) \

net/ipv4/ip_sockglue.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,8 @@ static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
790790
goto out_free_gsf;
791791

792792
err = set_mcast_msfilter(sk, gsf->gf_interface, gsf->gf_numsrc,
793-
gsf->gf_fmode, &gsf->gf_group, gsf->gf_slist);
793+
gsf->gf_fmode, &gsf->gf_group,
794+
gsf->gf_slist_flex);
794795
out_free_gsf:
795796
kfree(gsf);
796797
return err;
@@ -799,7 +800,7 @@ static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
799800
static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
800801
int optlen)
801802
{
802-
const int size0 = offsetof(struct compat_group_filter, gf_slist);
803+
const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
803804
struct compat_group_filter *gf32;
804805
unsigned int n;
805806
void *p;
@@ -813,7 +814,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
813814
p = kmalloc(optlen + 4, GFP_KERNEL);
814815
if (!p)
815816
return -ENOMEM;
816-
gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
817+
gf32 = p + 4; /* we want ->gf_group and ->gf_slist_flex aligned */
817818

818819
err = -EFAULT;
819820
if (copy_from_sockptr(gf32, optval, optlen))
@@ -826,15 +827,15 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
826827
goto out_free_gsf;
827828

828829
err = -EINVAL;
829-
if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
830+
if (offsetof(struct compat_group_filter, gf_slist_flex[n]) > optlen)
830831
goto out_free_gsf;
831832

832833
/* numsrc >= (4G-140)/128 overflow in 32 bits */
833834
err = -ENOBUFS;
834835
if (n > sock_net(sk)->ipv4.sysctl_igmp_max_msf)
835836
goto out_free_gsf;
836837
err = set_mcast_msfilter(sk, gf32->gf_interface, n, gf32->gf_fmode,
837-
&gf32->gf_group, gf32->gf_slist);
838+
&gf32->gf_group, gf32->gf_slist_flex);
838839
out_free_gsf:
839840
kfree(p);
840841
return err;
@@ -1455,7 +1456,7 @@ static bool getsockopt_needs_rtnl(int optname)
14551456
static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
14561457
int __user *optlen, int len)
14571458
{
1458-
const int size0 = offsetof(struct group_filter, gf_slist);
1459+
const int size0 = offsetof(struct group_filter, gf_slist_flex);
14591460
struct group_filter __user *p = optval;
14601461
struct group_filter gsf;
14611462
int num;
@@ -1467,7 +1468,7 @@ static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
14671468
return -EFAULT;
14681469

14691470
num = gsf.gf_numsrc;
1470-
err = ip_mc_gsfget(sk, &gsf, p->gf_slist);
1471+
err = ip_mc_gsfget(sk, &gsf, p->gf_slist_flex);
14711472
if (err)
14721473
return err;
14731474
if (gsf.gf_numsrc < num)
@@ -1481,7 +1482,7 @@ static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
14811482
static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
14821483
int __user *optlen, int len)
14831484
{
1484-
const int size0 = offsetof(struct compat_group_filter, gf_slist);
1485+
const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
14851486
struct compat_group_filter __user *p = optval;
14861487
struct compat_group_filter gf32;
14871488
struct group_filter gf;
@@ -1498,7 +1499,7 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
14981499
num = gf.gf_numsrc = gf32.gf_numsrc;
14991500
gf.gf_group = gf32.gf_group;
15001501

1501-
err = ip_mc_gsfget(sk, &gf, p->gf_slist);
1502+
err = ip_mc_gsfget(sk, &gf, p->gf_slist_flex);
15021503
if (err)
15031504
return err;
15041505
if (gf.gf_numsrc < num)

net/ipv6/ipv6_sockglue.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
225225
if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen)
226226
goto out_free_gsf;
227227

228-
ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist);
228+
ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist_flex);
229229
out_free_gsf:
230230
kfree(gsf);
231231
return ret;
@@ -234,7 +234,7 @@ static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
234234
static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
235235
int optlen)
236236
{
237-
const int size0 = offsetof(struct compat_group_filter, gf_slist);
237+
const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
238238
struct compat_group_filter *gf32;
239239
void *p;
240240
int ret;
@@ -249,7 +249,7 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
249249
if (!p)
250250
return -ENOMEM;
251251

252-
gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
252+
gf32 = p + 4; /* we want ->gf_group and ->gf_slist_flex aligned */
253253
ret = -EFAULT;
254254
if (copy_from_sockptr(gf32, optval, optlen))
255255
goto out_free_p;
@@ -261,14 +261,14 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
261261
goto out_free_p;
262262

263263
ret = -EINVAL;
264-
if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
264+
if (offsetof(struct compat_group_filter, gf_slist_flex[n]) > optlen)
265265
goto out_free_p;
266266

267267
ret = ip6_mc_msfilter(sk, &(struct group_filter){
268268
.gf_interface = gf32->gf_interface,
269269
.gf_group = gf32->gf_group,
270270
.gf_fmode = gf32->gf_fmode,
271-
.gf_numsrc = gf32->gf_numsrc}, gf32->gf_slist);
271+
.gf_numsrc = gf32->gf_numsrc}, gf32->gf_slist_flex);
272272

273273
out_free_p:
274274
kfree(p);
@@ -1048,7 +1048,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
10481048
static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
10491049
int __user *optlen, int len)
10501050
{
1051-
const int size0 = offsetof(struct group_filter, gf_slist);
1051+
const int size0 = offsetof(struct group_filter, gf_slist_flex);
10521052
struct group_filter __user *p = optval;
10531053
struct group_filter gsf;
10541054
int num;
@@ -1062,7 +1062,7 @@ static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
10621062
return -EADDRNOTAVAIL;
10631063
num = gsf.gf_numsrc;
10641064
lock_sock(sk);
1065-
err = ip6_mc_msfget(sk, &gsf, p->gf_slist);
1065+
err = ip6_mc_msfget(sk, &gsf, p->gf_slist_flex);
10661066
if (!err) {
10671067
if (num > gsf.gf_numsrc)
10681068
num = gsf.gf_numsrc;
@@ -1077,7 +1077,7 @@ static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
10771077
static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval,
10781078
int __user *optlen)
10791079
{
1080-
const int size0 = offsetof(struct compat_group_filter, gf_slist);
1080+
const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
10811081
struct compat_group_filter __user *p = optval;
10821082
struct compat_group_filter gf32;
10831083
struct group_filter gf;
@@ -1100,7 +1100,7 @@ static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval,
11001100
return -EADDRNOTAVAIL;
11011101

11021102
lock_sock(sk);
1103-
err = ip6_mc_msfget(sk, &gf, p->gf_slist);
1103+
err = ip6_mc_msfget(sk, &gf, p->gf_slist_flex);
11041104
release_sock(sk);
11051105
if (err)
11061106
return err;

0 commit comments

Comments
 (0)