From nobody Sat Feb 7 22:07:10 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 72B63273F9; Mon, 5 Jan 2026 06:45:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767595533; cv=none; b=Q9OXhDL4QpAWoFLPkJu+gw/t6xna8q3QuzopGgNTtpHqZ7VRAeJiorbJwwc39B+qAW6PV5YS326iVAo3sQxbsUbT9YPai7DL5J8Is0PsgvKeP5yQtz9vHAPtDhPWEWGjxqn0/nAFhaoiwknqfYvNhfrfB0w//XQFU6ozfYk7RVU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767595533; c=relaxed/simple; bh=39+dp+LyKV9XXcRP1+Darn1hWmdC9rX82dbhenXJ4ik=; h=Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type: Content-Disposition; b=hgeQZcn2K38t6HnI2fwloXILhwMgRqPctjFpH/eQxfaVf8H/CB3FFt2k5rKoIRCbMlUD/K+8cVGHA3dIFgkpkpYvGL6JdrtG2hjW/+c6Enwgy1JxcF/r5IN2m9ACfrYX7wa7FEB/G5VVoX5spmwqwC84r6n5G0N7DF1pQt5Wj9s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DjaBVkgA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DjaBVkgA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6905CC19421; Mon, 5 Jan 2026 06:45:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767595533; bh=39+dp+LyKV9XXcRP1+Darn1hWmdC9rX82dbhenXJ4ik=; h=Date:From:To:Cc:Subject:From; b=DjaBVkgAKoLplSExx5GK+fkIILn2fyoXuziP/zthkg3qO3Ku5XWdFNiILMjAuesFD ni+SUfq9C7jAT4GKcvBTZZRN5B/EbCmj4Srr9sHpon7yzCzek9rTjP88hCFyMkxPP1 V2PosWUUeU59qeUEq0RbWKK0UjKlM/Z30K+R2ZNcQsAFREgrzUVVV8k7F085fvSGEm MXkZ+GfXIu39DY+6eNsdilu2L85Mj1p6mO+1UmRJpYnaqA0A0sW6MeT5o8janyZoId K+1ClpbZZL5PvY3bN/uNCCCzcGXPtZuU0Acn98aoXlZCmXB1dE5Opvss9ANaFFyCrf 5uloDS7ggNAEA== Date: Mon, 5 Jan 2026 15:45:25 +0900 From: "Gustavo A. R. Silva" To: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , David Ahern , Willem de Bruijn Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, "Gustavo A. R. Silva" , linux-hardening@vger.kernel.org, Kees Cook Subject: [PATCH v2][next] ipv4/inet_sock.h: Avoid thousands of -Wflex-array-member-not-at-end warnings Message-ID: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Use DEFINE_RAW_FLEX() to avoid thousands of -Wflex-array-member-not-at-end warnings. Remove struct ip_options_data, and adjust the rest of the code so that flexible-array member struct ip_options_rcu::opt.__data[] ends last in struct icmp_bxm. Compensate for this by using the DEFINE_RAW_FLEX() helper to define each on-stack struct instance that contained struct ip_options_data as a member, and to define struct ip_options_rcu with a fixed on-stack size for its nested flexible-array member opt.__data[]. Also, add a couple of code comments to prevent people from adding members to a struct after another member that contains a flexible array. With these changes, fix 2600 warnings of the following type: include/net/inet_sock.h:65:33: warning: structure containing a flexible arr= ay member is not at the end of another structure [-Wflex-array-member-not-a= t-end] Signed-off-by: Gustavo A. R. Silva --- Changes in v2: - Use the DEFINE_RAW_FLEX() helper. - Update subject and changelog text. include/net/inet_sock.h | 9 ++-- net/ipv4/icmp.c | 108 +++++++++++++++++++++------------------- net/ipv4/ip_output.c | 13 ++--- net/ipv4/ping.c | 7 +-- net/ipv4/raw.c | 7 +-- net/ipv4/udp.c | 7 +-- 6 files changed, 81 insertions(+), 70 deletions(-) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index ac1c75975908..3370159556b8 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -26,6 +26,8 @@ #include #include =20 +#define IP_OPTIONS_DATA_FIXED_SIZE 40 + /** struct ip_options - IP Options * * @faddr - Saved first hop address @@ -58,12 +60,9 @@ struct ip_options { =20 struct ip_options_rcu { struct rcu_head rcu; - struct ip_options opt; -}; =20 -struct ip_options_data { - struct ip_options_rcu opt; - char data[40]; + /* Must be last as it ends in a flexible-array member. */ + struct ip_options opt; }; =20 struct inet_request_sock { diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 4abbec2f47ef..19c9c838967f 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -112,7 +112,9 @@ struct icmp_bxm { __be32 times[3]; } data; int head_len; - struct ip_options_data replyopts; + + /* Must be last as it ends in a flexible-array member. */ + struct ip_options_rcu replyopts; }; =20 /* An array of errno for error messages from dest unreach. */ @@ -353,9 +355,12 @@ void icmp_out_count(struct net *net, unsigned char typ= e) static int icmp_glue_bits(void *from, char *to, int offset, int len, int o= dd, struct sk_buff *skb) { - struct icmp_bxm *icmp_param =3D from; + DEFINE_RAW_FLEX(struct icmp_bxm, icmp_param, replyopts.opt.__data, + IP_OPTIONS_DATA_FIXED_SIZE); __wsum csum; =20 + icmp_param =3D from; + csum =3D skb_copy_and_csum_bits(icmp_param->skb, icmp_param->offset + offset, to, len); @@ -413,7 +418,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, str= uct sk_buff *skb) int type =3D icmp_param->data.icmph.type; int code =3D icmp_param->data.icmph.code; =20 - if (ip_options_echo(net, &icmp_param->replyopts.opt.opt, skb)) + if (ip_options_echo(net, &icmp_param->replyopts.opt, skb)) return; =20 /* Needed by both icmpv4_global_allow and icmp_xmit_lock */ @@ -435,10 +440,10 @@ static void icmp_reply(struct icmp_bxm *icmp_param, s= truct sk_buff *skb) daddr =3D ipc.addr =3D ip_hdr(skb)->saddr; saddr =3D fib_compute_spec_dst(skb); =20 - if (icmp_param->replyopts.opt.opt.optlen) { - ipc.opt =3D &icmp_param->replyopts.opt; + if (icmp_param->replyopts.opt.optlen) { + ipc.opt =3D &icmp_param->replyopts; if (ipc.opt->opt.srr) - daddr =3D icmp_param->replyopts.opt.opt.faddr; + daddr =3D icmp_param->replyopts.opt.faddr; } memset(&fl4, 0, sizeof(fl4)); fl4.daddr =3D daddr; @@ -491,8 +496,8 @@ static struct rtable *icmp_route_lookup(struct net *net= , struct flowi4 *fl4, int err; =20 memset(fl4, 0, sizeof(*fl4)); - fl4->daddr =3D (param->replyopts.opt.opt.srr ? - param->replyopts.opt.opt.faddr : iph->saddr); + fl4->daddr =3D (param->replyopts.opt.srr ? + param->replyopts.opt.faddr : iph->saddr); fl4->saddr =3D saddr; fl4->flowi4_mark =3D mark; fl4->flowi4_uid =3D sock_net_uid(net, NULL); @@ -775,9 +780,10 @@ icmp_ext_append(struct net *net, struct sk_buff *skb_i= n, struct icmphdr *icmph, void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info, const struct inet_skb_parm *parm) { + DEFINE_RAW_FLEX(struct icmp_bxm, icmp_param, replyopts.opt.__data, + IP_OPTIONS_DATA_FIXED_SIZE); struct iphdr *iph; int room; - struct icmp_bxm icmp_param; struct rtable *rt =3D skb_rtable(skb_in); bool apply_ratelimit =3D false; struct sk_buff *ext_skb; @@ -906,7 +912,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int = code, __be32 info, iph->tos; mark =3D IP4_REPLY_MARK(net, skb_in->mark); =20 - if (__ip_options_echo(net, &icmp_param.replyopts.opt.opt, skb_in, + if (__ip_options_echo(net, &icmp_param->replyopts.opt, skb_in, &parm->opt)) goto out_unlock; =20 @@ -915,21 +921,21 @@ void __icmp_send(struct sk_buff *skb_in, int type, in= t code, __be32 info, * Prepare data for ICMP header. */ =20 - icmp_param.data.icmph.type =3D type; - icmp_param.data.icmph.code =3D code; - icmp_param.data.icmph.un.gateway =3D info; - icmp_param.data.icmph.checksum =3D 0; - icmp_param.skb =3D skb_in; - icmp_param.offset =3D skb_network_offset(skb_in); + icmp_param->data.icmph.type =3D type; + icmp_param->data.icmph.code =3D code; + icmp_param->data.icmph.un.gateway =3D info; + icmp_param->data.icmph.checksum =3D 0; + icmp_param->skb =3D skb_in; + icmp_param->offset =3D skb_network_offset(skb_in); ipcm_init(&ipc); ipc.tos =3D tos; ipc.addr =3D iph->saddr; - ipc.opt =3D &icmp_param.replyopts.opt; + ipc.opt =3D &icmp_param->replyopts; ipc.sockc.mark =3D mark; =20 rt =3D icmp_route_lookup(net, &fl4, skb_in, iph, saddr, inet_dsfield_to_dscp(tos), mark, type, code, - &icmp_param); + icmp_param); if (IS_ERR(rt)) goto out_unlock; =20 @@ -942,7 +948,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int = code, __be32 info, room =3D dst_mtu(&rt->dst); if (room > 576) room =3D 576; - room -=3D sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen; + room -=3D sizeof(struct iphdr) + icmp_param->replyopts.opt.optlen; room -=3D sizeof(struct icmphdr); /* Guard against tiny mtu. We need to include at least one * IP network header for this message to make any sense. @@ -950,15 +956,15 @@ void __icmp_send(struct sk_buff *skb_in, int type, in= t code, __be32 info, if (room <=3D (int)sizeof(struct iphdr)) goto ende; =20 - ext_skb =3D icmp_ext_append(net, skb_in, &icmp_param.data.icmph, room, + ext_skb =3D icmp_ext_append(net, skb_in, &icmp_param->data.icmph, room, parm->iif); if (ext_skb) - icmp_param.skb =3D ext_skb; + icmp_param->skb =3D ext_skb; =20 - icmp_param.data_len =3D icmp_param.skb->len - icmp_param.offset; - if (icmp_param.data_len > room) - icmp_param.data_len =3D room; - icmp_param.head_len =3D sizeof(struct icmphdr); + icmp_param->data_len =3D icmp_param->skb->len - icmp_param->offset; + if (icmp_param->data_len > room) + icmp_param->data_len =3D room; + icmp_param->head_len =3D sizeof(struct icmphdr); =20 /* if we don't have a source address at this point, fall back to the * dummy address instead of sending out a packet with a source address @@ -969,7 +975,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int = code, __be32 info, =20 trace_icmp_send(skb_in, type, code); =20 - icmp_push_reply(sk, &icmp_param, &fl4, &ipc, &rt); + icmp_push_reply(sk, icmp_param, &fl4, &ipc, &rt); =20 if (ext_skb) consume_skb(ext_skb); @@ -1206,7 +1212,8 @@ static enum skb_drop_reason icmp_redirect(struct sk_b= uff *skb) =20 static enum skb_drop_reason icmp_echo(struct sk_buff *skb) { - struct icmp_bxm icmp_param; + DEFINE_RAW_FLEX(struct icmp_bxm, icmp_param, replyopts.opt.__data, + IP_OPTIONS_DATA_FIXED_SIZE); struct net *net; =20 net =3D skb_dst_dev_net_rcu(skb); @@ -1214,18 +1221,18 @@ static enum skb_drop_reason icmp_echo(struct sk_buf= f *skb) if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all)) return SKB_NOT_DROPPED_YET; =20 - icmp_param.data.icmph =3D *icmp_hdr(skb); - icmp_param.skb =3D skb; - icmp_param.offset =3D 0; - icmp_param.data_len =3D skb->len; - icmp_param.head_len =3D sizeof(struct icmphdr); + icmp_param->data.icmph =3D *icmp_hdr(skb); + icmp_param->skb =3D skb; + icmp_param->offset =3D 0; + icmp_param->data_len =3D skb->len; + icmp_param->head_len =3D sizeof(struct icmphdr); =20 - if (icmp_param.data.icmph.type =3D=3D ICMP_ECHO) - icmp_param.data.icmph.type =3D ICMP_ECHOREPLY; - else if (!icmp_build_probe(skb, &icmp_param.data.icmph)) + if (icmp_param->data.icmph.type =3D=3D ICMP_ECHO) + icmp_param->data.icmph.type =3D ICMP_ECHOREPLY; + else if (!icmp_build_probe(skb, &icmp_param->data.icmph)) return SKB_NOT_DROPPED_YET; =20 - icmp_reply(&icmp_param, skb); + icmp_reply(icmp_param, skb); return SKB_NOT_DROPPED_YET; } =20 @@ -1353,7 +1360,8 @@ EXPORT_SYMBOL_GPL(icmp_build_probe); */ static enum skb_drop_reason icmp_timestamp(struct sk_buff *skb) { - struct icmp_bxm icmp_param; + DEFINE_RAW_FLEX(struct icmp_bxm, icmp_param, replyopts.opt.__data, + IP_OPTIONS_DATA_FIXED_SIZE); /* * Too short. */ @@ -1363,19 +1371,19 @@ static enum skb_drop_reason icmp_timestamp(struct s= k_buff *skb) /* * Fill in the current time as ms since midnight UT: */ - icmp_param.data.times[1] =3D inet_current_timestamp(); - icmp_param.data.times[2] =3D icmp_param.data.times[1]; - - BUG_ON(skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)); - - icmp_param.data.icmph =3D *icmp_hdr(skb); - icmp_param.data.icmph.type =3D ICMP_TIMESTAMPREPLY; - icmp_param.data.icmph.code =3D 0; - icmp_param.skb =3D skb; - icmp_param.offset =3D 0; - icmp_param.data_len =3D 0; - icmp_param.head_len =3D sizeof(struct icmphdr) + 12; - icmp_reply(&icmp_param, skb); + icmp_param->data.times[1] =3D inet_current_timestamp(); + icmp_param->data.times[2] =3D icmp_param->data.times[1]; + + BUG_ON(skb_copy_bits(skb, 0, &icmp_param->data.times[0], 4)); + + icmp_param->data.icmph =3D *icmp_hdr(skb); + icmp_param->data.icmph.type =3D ICMP_TIMESTAMPREPLY; + icmp_param->data.icmph.code =3D 0; + icmp_param->skb =3D skb; + icmp_param->offset =3D 0; + icmp_param->data_len =3D 0; + icmp_param->head_len =3D sizeof(struct icmphdr) + 12; + icmp_reply(icmp_param, skb); return SKB_NOT_DROPPED_YET; =20 out_err: diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ff11d3a85a36..75fcb58795bb 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1606,7 +1606,8 @@ void ip_send_unicast_reply(struct sock *sk, const str= uct sock *orig_sk, const struct ip_reply_arg *arg, unsigned int len, u64 transmit_time, u32 txhash) { - struct ip_options_data replyopts; + DEFINE_RAW_FLEX(struct ip_options_rcu, replyopts, opt.__data, + IP_OPTIONS_DATA_FIXED_SIZE); struct ipcm_cookie ipc; struct flowi4 fl4; struct rtable *rt =3D skb_rtable(skb); @@ -1615,18 +1616,18 @@ void ip_send_unicast_reply(struct sock *sk, const s= truct sock *orig_sk, int err; int oif; =20 - if (__ip_options_echo(net, &replyopts.opt.opt, skb, sopt)) + if (__ip_options_echo(net, &replyopts->opt, skb, sopt)) return; =20 ipcm_init(&ipc); ipc.addr =3D daddr; ipc.sockc.transmit_time =3D transmit_time; =20 - if (replyopts.opt.opt.optlen) { - ipc.opt =3D &replyopts.opt; + if (replyopts->opt.optlen) { + ipc.opt =3D replyopts; =20 - if (replyopts.opt.opt.srr) - daddr =3D replyopts.opt.opt.faddr; + if (replyopts->opt.srr) + daddr =3D replyopts->opt.faddr; } =20 oif =3D arg->bound_dev_if; diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index ad56588107cc..7e2812668350 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -690,6 +690,8 @@ EXPORT_IPV6_MOD_GPL(ping_common_sendmsg); =20 static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { + DEFINE_RAW_FLEX(struct ip_options_rcu, opt_copy, opt.__data, + IP_OPTIONS_DATA_FIXED_SIZE); struct net *net =3D sock_net(sk); struct flowi4 fl4; struct inet_sock *inet =3D inet_sk(sk); @@ -697,7 +699,6 @@ static int ping_v4_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t len) struct icmphdr user_icmph; struct pingfakehdr pfh; struct rtable *rt =3D NULL; - struct ip_options_data opt_copy; int free =3D 0; __be32 saddr, daddr, faddr; u8 scope; @@ -746,9 +747,9 @@ static int ping_v4_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t len) rcu_read_lock(); inet_opt =3D rcu_dereference(inet->inet_opt); if (inet_opt) { - memcpy(&opt_copy, inet_opt, + memcpy(opt_copy, inet_opt, sizeof(*inet_opt) + inet_opt->opt.optlen); - ipc.opt =3D &opt_copy.opt; + ipc.opt =3D opt_copy; } rcu_read_unlock(); } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 5998c4cc6f47..e20c41206e29 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -481,6 +481,8 @@ static int raw_getfrag(void *from, char *to, int offset= , int len, int odd, =20 static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { + DEFINE_RAW_FLEX(struct ip_options_rcu, opt_copy, opt.__data, + IP_OPTIONS_DATA_FIXED_SIZE); struct inet_sock *inet =3D inet_sk(sk); struct net *net =3D sock_net(sk); struct ipcm_cookie ipc; @@ -491,7 +493,6 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *= msg, size_t len) __be32 daddr; __be32 saddr; int uc_index, err; - struct ip_options_data opt_copy; struct raw_frag_vec rfv; int hdrincl; =20 @@ -561,9 +562,9 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *= msg, size_t len) rcu_read_lock(); inet_opt =3D rcu_dereference(inet->inet_opt); if (inet_opt) { - memcpy(&opt_copy, inet_opt, + memcpy(opt_copy, inet_opt, sizeof(*inet_opt) + inet_opt->opt.optlen); - ipc.opt =3D &opt_copy.opt; + ipc.opt =3D opt_copy; } rcu_read_unlock(); } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ffe074cb5865..591527ae811c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1269,6 +1269,8 @@ EXPORT_IPV6_MOD_GPL(udp_cmsg_send); =20 int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { + DEFINE_RAW_FLEX(struct ip_options_rcu, opt_copy, opt.__data, + IP_OPTIONS_DATA_FIXED_SIZE); struct inet_sock *inet =3D inet_sk(sk); struct udp_sock *up =3D udp_sk(sk); DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); @@ -1286,7 +1288,6 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, = size_t len) int corkreq =3D udp_test_bit(CORK, sk) || msg->msg_flags & MSG_MORE; int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); struct sk_buff *skb; - struct ip_options_data opt_copy; int uc_index; =20 if (len > 0xFFFF) @@ -1368,9 +1369,9 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, = size_t len) rcu_read_lock(); inet_opt =3D rcu_dereference(inet->inet_opt); if (inet_opt) { - memcpy(&opt_copy, inet_opt, + memcpy(opt_copy, inet_opt, sizeof(*inet_opt) + inet_opt->opt.optlen); - ipc.opt =3D &opt_copy.opt; + ipc.opt =3D opt_copy; } rcu_read_unlock(); } --=20 2.43.0