mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-08 00:29:36 -04:00
ipv6: Validate RTA_GATEWAY of RTA_MULTIPATH in rtm_to_fib6_config().
We will perform RTM_NEWROUTE and RTM_DELROUTE under RCU, and then we want to perform some validation out of the RCU scope. When creating / removing an IPv6 route with RTA_MULTIPATH, inet6_rtm_newroute() / inet6_rtm_delroute() validates RTA_GATEWAY in each multipath entry. Let's do that in rtm_to_fib6_config(). Note that now RTM_DELROUTE returns an error for RTA_MULTIPATH with 0 entries, which was accepted but should result in -EINVAL as RTM_NEWROUTE. Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com> Link: https://patch.msgid.link/20250418000443.43734-2-kuniyu@amazon.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
committed by
Paolo Abeni
parent
abcec3ed92
commit
4cb4861d8c
@@ -5051,6 +5051,44 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
|
||||
[RTA_FLOWLABEL] = { .type = NLA_BE32 },
|
||||
};
|
||||
|
||||
static int rtm_to_fib6_multipath_config(struct fib6_config *cfg,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct rtnexthop *rtnh;
|
||||
int remaining;
|
||||
|
||||
remaining = cfg->fc_mp_len;
|
||||
rtnh = (struct rtnexthop *)cfg->fc_mp;
|
||||
|
||||
if (!rtnh_ok(rtnh, remaining)) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid nexthop configuration - no valid nexthops");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
do {
|
||||
int attrlen = rtnh_attrlen(rtnh);
|
||||
|
||||
if (attrlen > 0) {
|
||||
struct nlattr *nla, *attrs;
|
||||
|
||||
attrs = rtnh_attrs(rtnh);
|
||||
nla = nla_find(attrs, attrlen, RTA_GATEWAY);
|
||||
if (nla) {
|
||||
if (nla_len(nla) < sizeof(cfg->fc_gateway)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Invalid IPv6 address in RTA_GATEWAY");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rtnh = rtnh_next(rtnh, &remaining);
|
||||
} while (rtnh_ok(rtnh, remaining));
|
||||
|
||||
return lwtunnel_valid_encap_type_attr(cfg->fc_mp, cfg->fc_mp_len,
|
||||
extack, true);
|
||||
}
|
||||
|
||||
static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct fib6_config *cfg,
|
||||
struct netlink_ext_ack *extack)
|
||||
@@ -5165,9 +5203,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
|
||||
cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
|
||||
|
||||
err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
|
||||
cfg->fc_mp_len,
|
||||
extack, true);
|
||||
err = rtm_to_fib6_multipath_config(cfg, extack);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
}
|
||||
@@ -5287,19 +5323,6 @@ static bool ip6_route_mpath_should_notify(const struct fib6_info *rt)
|
||||
return should_notify;
|
||||
}
|
||||
|
||||
static int fib6_gw_from_attr(struct in6_addr *gw, struct nlattr *nla,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (nla_len(nla) < sizeof(*gw)) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid IPv6 address in RTA_GATEWAY");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*gw = nla_get_in6_addr(nla);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ip6_route_multipath_add(struct fib6_config *cfg,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
@@ -5340,18 +5363,11 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
|
||||
|
||||
nla = nla_find(attrs, attrlen, RTA_GATEWAY);
|
||||
if (nla) {
|
||||
err = fib6_gw_from_attr(&r_cfg.fc_gateway, nla,
|
||||
extack);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
r_cfg.fc_gateway = nla_get_in6_addr(nla);
|
||||
r_cfg.fc_flags |= RTF_GATEWAY;
|
||||
}
|
||||
r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
|
||||
|
||||
/* RTA_ENCAP_TYPE length checked in
|
||||
* lwtunnel_valid_encap_type_attr
|
||||
*/
|
||||
r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
|
||||
nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
|
||||
if (nla)
|
||||
r_cfg.fc_encap_type = nla_get_u16(nla);
|
||||
@@ -5384,12 +5400,6 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
|
||||
rtnh = rtnh_next(rtnh, &remaining);
|
||||
}
|
||||
|
||||
if (list_empty(&rt6_nh_list)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Invalid nexthop configuration - no valid nexthops");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* for add and replace send one notification with all nexthops.
|
||||
* Skip the notification in fib6_add_rt2node and send one with
|
||||
* the full route when done
|
||||
@@ -5511,21 +5521,15 @@ static int ip6_route_multipath_del(struct fib6_config *cfg,
|
||||
|
||||
nla = nla_find(attrs, attrlen, RTA_GATEWAY);
|
||||
if (nla) {
|
||||
err = fib6_gw_from_attr(&r_cfg.fc_gateway, nla,
|
||||
extack);
|
||||
if (err) {
|
||||
last_err = err;
|
||||
goto next_rtnh;
|
||||
}
|
||||
|
||||
r_cfg.fc_gateway = nla_get_in6_addr(nla);
|
||||
r_cfg.fc_flags |= RTF_GATEWAY;
|
||||
}
|
||||
}
|
||||
|
||||
err = ip6_route_del(&r_cfg, extack);
|
||||
if (err)
|
||||
last_err = err;
|
||||
|
||||
next_rtnh:
|
||||
rtnh = rtnh_next(rtnh, &remaining);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user