Commit c92bf26c authored by Jakub Kicinski's avatar Jakub Kicinski Committed by Paolo Abeni

rtnl: allocate more attr tables on the heap

Commit a2939745 ("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: default avatarKalle Valo <kvalo@kernel.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Tested-by: default avatarKalle Valo <kvalo@kernel.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent d7ab15ab
...@@ -3302,17 +3302,23 @@ static int rtnl_group_changelink(const struct sk_buff *skb, ...@@ -3302,17 +3302,23 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
return 0; 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, 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; unsigned char name_assign_type = NET_NAME_USER;
struct nlattr *linkinfo[IFLA_INFO_MAX + 1]; struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
struct nlattr ** const tb = tbs->tb;
const struct rtnl_link_ops *m_ops; const struct rtnl_link_ops *m_ops;
struct net_device *master_dev; struct net_device *master_dev;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
const struct rtnl_link_ops *ops; const struct rtnl_link_ops *ops;
struct nlattr *tb[IFLA_MAX + 1];
struct net *dest_net, *link_net; struct net *dest_net, *link_net;
struct nlattr **slave_data; struct nlattr **slave_data;
char kind[MODULE_NAME_LEN]; char kind[MODULE_NAME_LEN];
...@@ -3382,12 +3388,12 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -3382,12 +3388,12 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
return -EINVAL; return -EINVAL;
if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { 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], linkinfo[IFLA_INFO_DATA],
ops->policy, extack); ops->policy, extack);
if (err < 0) if (err < 0)
return err; return err;
data = attr; data = tbs->attr;
} }
if (ops->validate) { if (ops->validate) {
err = ops->validate(tb, data, extack); err = ops->validate(tb, data, extack);
...@@ -3403,14 +3409,14 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -3403,14 +3409,14 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
if (m_ops->slave_maxtype && if (m_ops->slave_maxtype &&
linkinfo[IFLA_INFO_SLAVE_DATA]) { linkinfo[IFLA_INFO_SLAVE_DATA]) {
err = nla_parse_nested_deprecated(slave_attr, err = nla_parse_nested_deprecated(tbs->slave_attr,
m_ops->slave_maxtype, m_ops->slave_maxtype,
linkinfo[IFLA_INFO_SLAVE_DATA], linkinfo[IFLA_INFO_SLAVE_DATA],
m_ops->slave_policy, m_ops->slave_policy,
extack); extack);
if (err < 0) if (err < 0)
return err; return err;
slave_data = slave_attr; slave_data = tbs->slave_attr;
} }
} }
...@@ -3559,15 +3565,15 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -3559,15 +3565,15 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct nlattr **attr; struct rtnl_newlink_tbs *tbs;
int ret; int ret;
attr = kmalloc_array(RTNL_MAX_TYPE + 1, sizeof(*attr), GFP_KERNEL); tbs = kmalloc(sizeof(*tbs), GFP_KERNEL);
if (!attr) if (!tbs)
return -ENOMEM; return -ENOMEM;
ret = __rtnl_newlink(skb, nlh, attr, extack); ret = __rtnl_newlink(skb, nlh, tbs, extack);
kfree(attr); kfree(tbs);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment