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

net: reduce rtnetlink_rcv_msg() stack usage

IFLA_MAX is increasing slowly but surely.

Some compilers use more than 512 bytes of stack in rtnetlink_rcv_msg()
because it calls rtnl_calcit() for RTM_GETLINK message.

Use noinline_for_stack attribute to not inline rtnl_calcit(),
and directly use nla_for_each_attr_type() (Jakub suggestion)
because we only care about IFLA_EXT_MASK at this stage.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20240710151653.3786604-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
cef4902b b07593ed

+12 -6
+12 -6
net/core/rtnetlink.c
··· 3969 3969 return rtnl_linkprop(RTM_DELLINKPROP, skb, nlh, extack); 3970 3970 } 3971 3971 3972 - static u32 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh) 3972 + static noinline_for_stack u32 rtnl_calcit(struct sk_buff *skb, 3973 + struct nlmsghdr *nlh) 3973 3974 { 3974 3975 struct net *net = sock_net(skb->sk); 3975 3976 size_t min_ifinfo_dump_size = 0; 3976 - struct nlattr *tb[IFLA_MAX+1]; 3977 3977 u32 ext_filter_mask = 0; 3978 3978 struct net_device *dev; 3979 - int hdrlen; 3979 + struct nlattr *nla; 3980 + int hdrlen, rem; 3980 3981 3981 3982 /* Same kernel<->userspace interface hack as in rtnl_dump_ifinfo. */ 3982 3983 hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ? 3983 3984 sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); 3984 3985 3985 - if (nlmsg_parse_deprecated(nlh, hdrlen, tb, IFLA_MAX, ifla_policy, NULL) >= 0) { 3986 - if (tb[IFLA_EXT_MASK]) 3987 - ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); 3986 + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) 3987 + return NLMSG_GOODSIZE; 3988 + 3989 + nla_for_each_attr_type(nla, IFLA_EXT_MASK, 3990 + nlmsg_attrdata(nlh, hdrlen), 3991 + nlmsg_attrlen(nlh, hdrlen), rem) { 3992 + if (nla_len(nla) == sizeof(u32)) 3993 + ext_filter_mask = nla_get_u32(nla); 3988 3994 } 3989 3995 3990 3996 if (!ext_filter_mask)