Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net/ipv4: Replace one-element array with flexible-array member

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:

$ pahole -C ip_msfilter net/ipv4/ip_sockglue.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 */
};

Also, refactor the code accordingly and make use of the struct_size()
and flex_array_size() helpers.

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: https://github.com/KSPP/linux/issues/79
Link: https://github.com/KSPP/linux/issues/109
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Gustavo A. R. Silva and committed by
David S. Miller
2d3e5caf 29a097b7

+30 -18
+16 -5
include/uapi/linux/in.h
··· 188 188 }; 189 189 190 190 struct ip_msfilter { 191 - __be32 imsf_multiaddr; 192 - __be32 imsf_interface; 193 - __u32 imsf_fmode; 194 - __u32 imsf_numsrc; 195 - __be32 imsf_slist[1]; 191 + union { 192 + struct { 193 + __be32 imsf_multiaddr_aux; 194 + __be32 imsf_interface_aux; 195 + __u32 imsf_fmode_aux; 196 + __u32 imsf_numsrc_aux; 197 + __be32 imsf_slist[1]; 198 + }; 199 + struct { 200 + __be32 imsf_multiaddr; 201 + __be32 imsf_interface; 202 + __u32 imsf_fmode; 203 + __u32 imsf_numsrc; 204 + __be32 imsf_slist_flex[]; 205 + }; 206 + }; 196 207 }; 197 208 198 209 #define IP_MSFILTER_SIZE(numsrc) \
+6 -6
net/ipv4/igmp.c
··· 2475 2475 goto done; 2476 2476 } 2477 2477 newpsl->sl_max = newpsl->sl_count = msf->imsf_numsrc; 2478 - memcpy(newpsl->sl_addr, msf->imsf_slist, 2479 - msf->imsf_numsrc * sizeof(msf->imsf_slist[0])); 2478 + memcpy(newpsl->sl_addr, msf->imsf_slist_flex, 2479 + flex_array_size(msf, imsf_slist_flex, msf->imsf_numsrc)); 2480 2480 err = ip_mc_add_src(in_dev, &msf->imsf_multiaddr, 2481 2481 msf->imsf_fmode, newpsl->sl_count, newpsl->sl_addr, 0); 2482 2482 if (err) { ··· 2551 2551 count = psl->sl_count; 2552 2552 } 2553 2553 copycount = count < msf->imsf_numsrc ? count : msf->imsf_numsrc; 2554 - len = copycount * sizeof(psl->sl_addr[0]); 2554 + len = flex_array_size(psl, sl_addr, copycount); 2555 2555 msf->imsf_numsrc = count; 2556 - if (put_user(IP_MSFILTER_SIZE(copycount), optlen) || 2557 - copy_to_user(optval, msf, IP_MSFILTER_SIZE(0))) { 2556 + if (put_user(struct_size(optval, imsf_slist_flex, copycount), optlen) || 2557 + copy_to_user(optval, msf, struct_size(optval, imsf_slist_flex, 0))) { 2558 2558 return -EFAULT; 2559 2559 } 2560 2560 if (len && 2561 - copy_to_user(&optval->imsf_slist[0], psl->sl_addr, len)) 2561 + copy_to_user(&optval->imsf_slist_flex[0], psl->sl_addr, len)) 2562 2562 return -EFAULT; 2563 2563 return 0; 2564 2564 done:
+8 -7
net/ipv4/ip_sockglue.c
··· 663 663 struct sockaddr_storage *group, 664 664 struct sockaddr_storage *list) 665 665 { 666 - int msize = IP_MSFILTER_SIZE(numsrc); 667 666 struct ip_msfilter *msf; 668 667 struct sockaddr_in *psin; 669 668 int err, i; 670 669 671 - msf = kmalloc(msize, GFP_KERNEL); 670 + msf = kmalloc(struct_size(msf, imsf_slist_flex, numsrc), GFP_KERNEL); 672 671 if (!msf) 673 672 return -ENOBUFS; 674 673 ··· 683 684 684 685 if (psin->sin_family != AF_INET) 685 686 goto Eaddrnotavail; 686 - msf->imsf_slist[i] = psin->sin_addr.s_addr; 687 + msf->imsf_slist_flex[i] = psin->sin_addr.s_addr; 687 688 } 688 689 err = ip_mc_msfilter(sk, msf, ifindex); 689 690 kfree(msf); ··· 1228 1229 { 1229 1230 struct ip_msfilter *msf; 1230 1231 1231 - if (optlen < IP_MSFILTER_SIZE(0)) 1232 + if (optlen < struct_size(msf, imsf_slist_flex, 0)) 1232 1233 goto e_inval; 1233 1234 if (optlen > sysctl_optmem_max) { 1234 1235 err = -ENOBUFS; ··· 1246 1247 err = -ENOBUFS; 1247 1248 break; 1248 1249 } 1249 - if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) { 1250 + if (struct_size(msf, imsf_slist_flex, msf->imsf_numsrc) > 1251 + optlen) { 1250 1252 kfree(msf); 1251 1253 err = -EINVAL; 1252 1254 break; ··· 1660 1660 { 1661 1661 struct ip_msfilter msf; 1662 1662 1663 - if (len < IP_MSFILTER_SIZE(0)) { 1663 + if (len < struct_size(&msf, imsf_slist_flex, 0)) { 1664 1664 err = -EINVAL; 1665 1665 goto out; 1666 1666 } 1667 - if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) { 1667 + if (copy_from_user(&msf, optval, 1668 + struct_size(&msf, imsf_slist_flex, 0))) { 1668 1669 err = -EFAULT; 1669 1670 goto out; 1670 1671 }