rtnl: allocate more attr tables on the heap
authorJakub Kicinski <kuba@kernel.org>
Fri, 29 Apr 2022 23:55:06 +0000 (16:55 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Mon, 2 May 2022 13:14:20 +0000 (15:14 +0200)
Commit a293974590cf ("rtnetlink: avoid frame size warning in rtnl_newlink()")
moved to allocating the largest attribute array of rtnl_newlink()
on the heap. Kalle reports the stack has grown above 1k again:

  net/core/rtnetlink.c:3557:1: error: the frame size of 1104 bytes is larger than 1024 bytes [-Werror=frame-larger-than=]

Move more attrs to the heap, wrap them in a struct.
Don't bother with linkinfo, it's referenced a lot and we take
its size so it's awkward to move, plus it's small (6 elements).

Reported-by: Kalle Valo <kvalo@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Tested-by: Kalle Valo <kvalo@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/core/rtnetlink.c

index 73f2cbc440c9bbf00f725be52448a6bdecd147a5..33919fd5c2021959a0a75fbbfe3e88cdb9a8a486 100644 (file)
@@ -3302,17 +3302,23 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
        return 0;
 }
 
+struct rtnl_newlink_tbs {
+       struct nlattr *tb[IFLA_MAX + 1];
+       struct nlattr *attr[RTNL_MAX_TYPE + 1];
+       struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
+};
+
 static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
-                         struct nlattr **attr, struct netlink_ext_ack *extack)
+                         struct rtnl_newlink_tbs *tbs,
+                         struct netlink_ext_ack *extack)
 {
-       struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
        unsigned char name_assign_type = NET_NAME_USER;
        struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
+       struct nlattr ** const tb = tbs->tb;
        const struct rtnl_link_ops *m_ops;
        struct net_device *master_dev;
        struct net *net = sock_net(skb->sk);
        const struct rtnl_link_ops *ops;
-       struct nlattr *tb[IFLA_MAX + 1];
        struct net *dest_net, *link_net;
        struct nlattr **slave_data;
        char kind[MODULE_NAME_LEN];
@@ -3382,12 +3388,12 @@ replay:
                        return -EINVAL;
 
                if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
-                       err = nla_parse_nested_deprecated(attr, ops->maxtype,
+                       err = nla_parse_nested_deprecated(tbs->attr, ops->maxtype,
                                                          linkinfo[IFLA_INFO_DATA],
                                                          ops->policy, extack);
                        if (err < 0)
                                return err;
-                       data = attr;
+                       data = tbs->attr;
                }
                if (ops->validate) {
                        err = ops->validate(tb, data, extack);
@@ -3403,14 +3409,14 @@ replay:
 
                if (m_ops->slave_maxtype &&
                    linkinfo[IFLA_INFO_SLAVE_DATA]) {
-                       err = nla_parse_nested_deprecated(slave_attr,
+                       err = nla_parse_nested_deprecated(tbs->slave_attr,
                                                          m_ops->slave_maxtype,
                                                          linkinfo[IFLA_INFO_SLAVE_DATA],
                                                          m_ops->slave_policy,
                                                          extack);
                        if (err < 0)
                                return err;
-                       slave_data = slave_attr;
+                       slave_data = tbs->slave_attr;
                }
        }
 
@@ -3559,15 +3565,15 @@ out_unregister:
 static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
                        struct netlink_ext_ack *extack)
 {
-       struct nlattr **attr;
+       struct rtnl_newlink_tbs *tbs;
        int ret;
 
-       attr = kmalloc_array(RTNL_MAX_TYPE + 1, sizeof(*attr), GFP_KERNEL);
-       if (!attr)
+       tbs = kmalloc(sizeof(*tbs), GFP_KERNEL);
+       if (!tbs)
                return -ENOMEM;
 
-       ret = __rtnl_newlink(skb, nlh, attr, extack);
-       kfree(attr);
+       ret = __rtnl_newlink(skb, nlh, tbs, extack);
+       kfree(tbs);
        return ret;
 }