]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/5.10.214/net-ipv4-ipv6-replace-one-element-arraya-with-flexib.patch
Linux 5.10.214
[thirdparty/kernel/stable-queue.git] / releases / 5.10.214 / net-ipv4-ipv6-replace-one-element-arraya-with-flexib.patch
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
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 From: Gustavo A. R. Silva <gustavoars@kernel.org>
10
11 [ Upstream commit db243b796439c0caba47865564d8acd18a301d18 ]
12
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].
17
18 Use an anonymous union with a couple of anonymous structs in order to
19 keep userspace unchanged and refactor the related code accordingly:
20
21 $ pahole -C group_filter net/ipv4/ip_sockglue.o
22 struct group_filter {
23 union {
24 struct {
25 __u32 gf_interface_aux; /* 0 4 */
26
27 /* XXX 4 bytes hole, try to pack */
28
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 */
34 }; /* 0 272 */
35 struct {
36 __u32 gf_interface; /* 0 4 */
37
38 /* XXX 4 bytes hole, try to pack */
39
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 */
45 }; /* 0 144 */
46 }; /* 0 272 */
47
48 /* size: 272, cachelines: 5, members: 1 */
49 /* last cacheline: 16 bytes */
50 };
51
52 $ pahole -C compat_group_filter net/ipv4/ip_sockglue.o
53 struct compat_group_filter {
54 union {
55 struct {
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 */
63 struct {
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 */
72
73 /* size: 268, cachelines: 5, members: 1 */
74 /* forced alignments: 1 */
75 /* last cacheline: 12 bytes */
76 } __attribute__((__packed__));
77
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
80 on memcpy().
81
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
84
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>
91 ---
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(-)
97
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 {
103 } __packed;
104
105 struct compat_group_filter {
106 - __u32 gf_interface;
107 - struct __kernel_sockaddr_storage gf_group
108 - __aligned(4);
109 - __u32 gf_fmode;
110 - __u32 gf_numsrc;
111 - struct __kernel_sockaddr_storage gf_slist[1]
112 - __aligned(4);
113 + union {
114 + struct {
115 + __u32 gf_interface_aux;
116 + struct __kernel_sockaddr_storage gf_group_aux
117 + __aligned(4);
118 + __u32 gf_fmode_aux;
119 + __u32 gf_numsrc_aux;
120 + struct __kernel_sockaddr_storage gf_slist[1]
121 + __aligned(4);
122 + } __packed;
123 + struct {
124 + __u32 gf_interface;
125 + struct __kernel_sockaddr_storage gf_group
126 + __aligned(4);
127 + __u32 gf_fmode;
128 + __u32 gf_numsrc;
129 + struct __kernel_sockaddr_storage gf_slist_flex[]
130 + __aligned(4);
131 + } __packed;
132 + };
133 } __packed;
134
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 {
141 };
142
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 */
149 + union {
150 + struct {
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 */
156 + };
157 + struct {
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 */
163 + };
164 + };
165 };
166
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)
173 goto out_free_gsf;
174
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);
179 out_free_gsf:
180 kfree(gsf);
181 return err;
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,
184 int optlen)
185 {
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;
189 unsigned int n;
190 void *p;
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);
193 if (!p)
194 return -ENOMEM;
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 */
197
198 err = -EFAULT;
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,
201 goto out_free_gsf;
202
203 err = -EINVAL;
204 - if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
205 + if (offsetof(struct compat_group_filter, gf_slist_flex[n]) > optlen)
206 goto out_free_gsf;
207
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))
211 goto out_free_gsf;
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);
215 out_free_gsf:
216 kfree(p);
217 return err;
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)
221 {
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;
226 int num;
227 @@ -1474,7 +1475,7 @@ static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
228 return -EFAULT;
229
230 num = gsf.gf_numsrc;
231 - err = ip_mc_gsfget(sk, &gsf, p->gf_slist);
232 + err = ip_mc_gsfget(sk, &gsf, p->gf_slist_flex);
233 if (err)
234 return err;
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)
239 {
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;
248
249 - err = ip_mc_gsfget(sk, &gf, p->gf_slist);
250 + err = ip_mc_gsfget(sk, &gf, p->gf_slist_flex);
251 if (err)
252 return err;
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)
260 goto out_free_gsf;
261
262 - ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist);
263 + ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist_flex);
264 out_free_gsf:
265 kfree(gsf);
266 return ret;
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,
269 int optlen)
270 {
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;
274 void *p;
275 int ret;
276 @@ -249,7 +249,7 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
277 if (!p)
278 return -ENOMEM;
279
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 */
282 ret = -EFAULT;
283 if (copy_from_sockptr(gf32, optval, optlen))
284 goto out_free_p;
285 @@ -261,14 +261,14 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
286 goto out_free_p;
287
288 ret = -EINVAL;
289 - if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
290 + if (offsetof(struct compat_group_filter, gf_slist_flex[n]) > optlen)
291 goto out_free_p;
292
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);
299
300 out_free_p:
301 kfree(p);
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)
305 {
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;
310 int num;
311 @@ -1065,7 +1065,7 @@ static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
312 return -EADDRNOTAVAIL;
313 num = gsf.gf_numsrc;
314 lock_sock(sk);
315 - err = ip6_mc_msfget(sk, &gsf, p->gf_slist);
316 + err = ip6_mc_msfget(sk, &gsf, p->gf_slist_flex);
317 if (!err) {
318 if (num > gsf.gf_numsrc)
319 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,
322 int __user *optlen)
323 {
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;
331
332 lock_sock(sk);
333 - err = ip6_mc_msfget(sk, &gf, p->gf_slist);
334 + err = ip6_mc_msfget(sk, &gf, p->gf_slist_flex);
335 release_sock(sk);
336 if (err)
337 return err;
338 --
339 2.43.0
340