1 From a3bfeae678c4101d4302ce962a218e96a79f021f Mon Sep 17 00:00:00 2001
2 From: Sasha Levin <sashal@kernel.org>
3 Date: Wed, 4 Aug 2021 15:45:36 -0500
4 Subject: net/ipv4/ipv6: Replace one-element arraya with flexible-array members
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 From: Gustavo A. R. Silva <gustavoars@kernel.org>
11 [ Upstream commit db243b796439c0caba47865564d8acd18a301d18 ]
13 There is a regular need in the kernel to provide a way to declare having
14 a dynamically sized set of trailing elements in a structure. Kernel code
15 should always use “flexible array members”[1] for these cases. The older
16 style of one-element or zero-length arrays should no longer be used[2].
18 Use an anonymous union with a couple of anonymous structs in order to
19 keep userspace unchanged and refactor the related code accordingly:
21 $ pahole -C group_filter net/ipv4/ip_sockglue.o
25 __u32 gf_interface_aux; /* 0 4 */
27 /* XXX 4 bytes hole, try to pack */
29 struct __kernel_sockaddr_storage gf_group_aux; /* 8 128 */
30 /* --- cacheline 2 boundary (128 bytes) was 8 bytes ago --- */
31 __u32 gf_fmode_aux; /* 136 4 */
32 __u32 gf_numsrc_aux; /* 140 4 */
33 struct __kernel_sockaddr_storage gf_slist[1]; /* 144 128 */
36 __u32 gf_interface; /* 0 4 */
38 /* XXX 4 bytes hole, try to pack */
40 struct __kernel_sockaddr_storage gf_group; /* 8 128 */
41 /* --- cacheline 2 boundary (128 bytes) was 8 bytes ago --- */
42 __u32 gf_fmode; /* 136 4 */
43 __u32 gf_numsrc; /* 140 4 */
44 struct __kernel_sockaddr_storage gf_slist_flex[0]; /* 144 0 */
48 /* size: 272, cachelines: 5, members: 1 */
49 /* last cacheline: 16 bytes */
52 $ pahole -C compat_group_filter net/ipv4/ip_sockglue.o
53 struct compat_group_filter {
56 __u32 gf_interface_aux; /* 0 4 */
57 struct __kernel_sockaddr_storage gf_group_aux __attribute__((__aligned__(4))); /* 4 128 */
58 /* --- cacheline 2 boundary (128 bytes) was 4 bytes ago --- */
59 __u32 gf_fmode_aux; /* 132 4 */
60 __u32 gf_numsrc_aux; /* 136 4 */
61 struct __kernel_sockaddr_storage gf_slist[1] __attribute__((__aligned__(4))); /* 140 128 */
62 } __attribute__((__packed__)) __attribute__((__aligned__(4))); /* 0 268 */
64 __u32 gf_interface; /* 0 4 */
65 struct __kernel_sockaddr_storage gf_group __attribute__((__aligned__(4))); /* 4 128 */
66 /* --- cacheline 2 boundary (128 bytes) was 4 bytes ago --- */
67 __u32 gf_fmode; /* 132 4 */
68 __u32 gf_numsrc; /* 136 4 */
69 struct __kernel_sockaddr_storage gf_slist_flex[0] __attribute__((__aligned__(4))); /* 140 0 */
70 } __attribute__((__packed__)) __attribute__((__aligned__(4))); /* 0 140 */
71 } __attribute__((__aligned__(1))); /* 0 268 */
73 /* size: 268, cachelines: 5, members: 1 */
74 /* forced alignments: 1 */
75 /* last cacheline: 12 bytes */
76 } __attribute__((__packed__));
78 This helps with the ongoing efforts to globally enable -Warray-bounds
79 and get us closer to being able to tighten the FORTIFY_SOURCE routines
82 [1] https://en.wikipedia.org/wiki/Flexible_array_member
83 [2] https://www.kernel.org/doc/html/v5.10/process/deprecated.html#zero-length-and-one-element-arrays
85 Link: https://github.com/KSPP/linux/issues/79
86 Link: https://github.com/KSPP/linux/issues/109
87 Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
88 Signed-off-by: David S. Miller <davem@davemloft.net>
89 Stable-dep-of: 5c3be3e0eb44 ("ipmr: fix incorrect parameter validation in the ip_mroute_getsockopt() function")
90 Signed-off-by: Sasha Levin <sashal@kernel.org>
92 include/net/compat.h | 27 ++++++++++++++++++++-------
93 include/uapi/linux/in.h | 21 ++++++++++++++++-----
94 net/ipv4/ip_sockglue.c | 19 ++++++++++---------
95 net/ipv6/ipv6_sockglue.c | 18 +++++++++---------
96 4 files changed, 55 insertions(+), 30 deletions(-)
98 diff --git a/include/net/compat.h b/include/net/compat.h
99 index 745db0d605b62..52bf5f0ee236b 100644
100 --- a/include/net/compat.h
101 +++ b/include/net/compat.h
102 @@ -81,13 +81,26 @@ struct compat_group_source_req {
105 struct compat_group_filter {
106 - __u32 gf_interface;
107 - struct __kernel_sockaddr_storage gf_group
111 - struct __kernel_sockaddr_storage gf_slist[1]
115 + __u32 gf_interface_aux;
116 + struct __kernel_sockaddr_storage gf_group_aux
118 + __u32 gf_fmode_aux;
119 + __u32 gf_numsrc_aux;
120 + struct __kernel_sockaddr_storage gf_slist[1]
124 + __u32 gf_interface;
125 + struct __kernel_sockaddr_storage gf_group
129 + struct __kernel_sockaddr_storage gf_slist_flex[]
135 #endif /* NET_COMPAT_H */
136 diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h
137 index 066098a5b9360..c4702fff64d3a 100644
138 --- a/include/uapi/linux/in.h
139 +++ b/include/uapi/linux/in.h
140 @@ -224,11 +224,22 @@ struct group_source_req {
143 struct group_filter {
144 - __u32 gf_interface; /* interface index */
145 - struct __kernel_sockaddr_storage gf_group; /* multicast address */
146 - __u32 gf_fmode; /* filter mode */
147 - __u32 gf_numsrc; /* number of sources */
148 - struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
151 + __u32 gf_interface_aux; /* interface index */
152 + struct __kernel_sockaddr_storage gf_group_aux; /* multicast address */
153 + __u32 gf_fmode_aux; /* filter mode */
154 + __u32 gf_numsrc_aux; /* number of sources */
155 + struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
158 + __u32 gf_interface; /* interface index */
159 + struct __kernel_sockaddr_storage gf_group; /* multicast address */
160 + __u32 gf_fmode; /* filter mode */
161 + __u32 gf_numsrc; /* number of sources */
162 + struct __kernel_sockaddr_storage gf_slist_flex[]; /* interface index */
167 #define GROUP_FILTER_SIZE(numsrc) \
168 diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
169 index 28b9b2e85f0be..9bea014309ded 100644
170 --- a/net/ipv4/ip_sockglue.c
171 +++ b/net/ipv4/ip_sockglue.c
172 @@ -797,7 +797,8 @@ static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
175 err = set_mcast_msfilter(sk, gsf->gf_interface, gsf->gf_numsrc,
176 - gsf->gf_fmode, &gsf->gf_group, gsf->gf_slist);
177 + gsf->gf_fmode, &gsf->gf_group,
178 + gsf->gf_slist_flex);
182 @@ -806,7 +807,7 @@ static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
183 static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
186 - const int size0 = offsetof(struct compat_group_filter, gf_slist);
187 + const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
188 struct compat_group_filter *gf32;
191 @@ -820,7 +821,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
192 p = kmalloc(optlen + 4, GFP_KERNEL);
195 - gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
196 + gf32 = p + 4; /* we want ->gf_group and ->gf_slist_flex aligned */
199 if (copy_from_sockptr(gf32, optval, optlen))
200 @@ -833,7 +834,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
204 - if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
205 + if (offsetof(struct compat_group_filter, gf_slist_flex[n]) > optlen)
208 /* numsrc >= (4G-140)/128 overflow in 32 bits */
209 @@ -841,7 +842,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
210 if (n > READ_ONCE(sock_net(sk)->ipv4.sysctl_igmp_max_msf))
212 err = set_mcast_msfilter(sk, gf32->gf_interface, n, gf32->gf_fmode,
213 - &gf32->gf_group, gf32->gf_slist);
214 + &gf32->gf_group, gf32->gf_slist_flex);
218 @@ -1462,7 +1463,7 @@ static bool getsockopt_needs_rtnl(int optname)
219 static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
220 int __user *optlen, int len)
222 - const int size0 = offsetof(struct group_filter, gf_slist);
223 + const int size0 = offsetof(struct group_filter, gf_slist_flex);
224 struct group_filter __user *p = optval;
225 struct group_filter gsf;
227 @@ -1474,7 +1475,7 @@ static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
231 - err = ip_mc_gsfget(sk, &gsf, p->gf_slist);
232 + err = ip_mc_gsfget(sk, &gsf, p->gf_slist_flex);
235 if (gsf.gf_numsrc < num)
236 @@ -1488,7 +1489,7 @@ static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
237 static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
238 int __user *optlen, int len)
240 - const int size0 = offsetof(struct compat_group_filter, gf_slist);
241 + const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
242 struct compat_group_filter __user *p = optval;
243 struct compat_group_filter gf32;
244 struct group_filter gf;
245 @@ -1505,7 +1506,7 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
246 num = gf.gf_numsrc = gf32.gf_numsrc;
247 gf.gf_group = gf32.gf_group;
249 - err = ip_mc_gsfget(sk, &gf, p->gf_slist);
250 + err = ip_mc_gsfget(sk, &gf, p->gf_slist_flex);
253 if (gf.gf_numsrc < num)
254 diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
255 index 7b4b457a8b87a..0ac527cd5d56d 100644
256 --- a/net/ipv6/ipv6_sockglue.c
257 +++ b/net/ipv6/ipv6_sockglue.c
258 @@ -225,7 +225,7 @@ static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
259 if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen)
262 - ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist);
263 + ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist_flex);
267 @@ -234,7 +234,7 @@ static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
268 static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
271 - const int size0 = offsetof(struct compat_group_filter, gf_slist);
272 + const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
273 struct compat_group_filter *gf32;
276 @@ -249,7 +249,7 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
280 - gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
281 + gf32 = p + 4; /* we want ->gf_group and ->gf_slist_flex aligned */
283 if (copy_from_sockptr(gf32, optval, optlen))
285 @@ -261,14 +261,14 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
289 - if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
290 + if (offsetof(struct compat_group_filter, gf_slist_flex[n]) > optlen)
293 ret = ip6_mc_msfilter(sk, &(struct group_filter){
294 .gf_interface = gf32->gf_interface,
295 .gf_group = gf32->gf_group,
296 .gf_fmode = gf32->gf_fmode,
297 - .gf_numsrc = gf32->gf_numsrc}, gf32->gf_slist);
298 + .gf_numsrc = gf32->gf_numsrc}, gf32->gf_slist_flex);
302 @@ -1051,7 +1051,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
303 static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
304 int __user *optlen, int len)
306 - const int size0 = offsetof(struct group_filter, gf_slist);
307 + const int size0 = offsetof(struct group_filter, gf_slist_flex);
308 struct group_filter __user *p = optval;
309 struct group_filter gsf;
311 @@ -1065,7 +1065,7 @@ static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
312 return -EADDRNOTAVAIL;
315 - err = ip6_mc_msfget(sk, &gsf, p->gf_slist);
316 + err = ip6_mc_msfget(sk, &gsf, p->gf_slist_flex);
318 if (num > gsf.gf_numsrc)
320 @@ -1080,7 +1080,7 @@ static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
321 static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval,
324 - const int size0 = offsetof(struct compat_group_filter, gf_slist);
325 + const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
326 struct compat_group_filter __user *p = optval;
327 struct compat_group_filter gf32;
328 struct group_filter gf;
329 @@ -1103,7 +1103,7 @@ static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval,
330 return -EADDRNOTAVAIL;
333 - err = ip6_mc_msfget(sk, &gf, p->gf_slist);
334 + err = ip6_mc_msfget(sk, &gf, p->gf_slist_flex);