2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

neighbour: Move neigh_find_table() to neigh_get().

neigh_valid_get_req() calls neigh_find_table() to fetch neigh_tables[].

neigh_find_table() uses rcu_dereference_rtnl(), but RTNL actually does
not protect it at all; neigh_table_clear() can be called without RTNL
and only waits for RCU readers by synchronize_rcu().

Fortunately, there is no bug because IPv4 is built-in, IPv6 cannot be
unloaded, and DECNET was removed.

To fetch neigh_tables[] by rcu_dereference() later, let's move
neigh_find_table() from neigh_valid_get_req() to neigh_get().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250716221221.442239-5-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Kuniyuki Iwashima 2025-07-16 22:08:09 +00:00 committed by Jakub Kicinski
parent 3dfe0b57dc
commit 0e5ac19c78

View File

@ -2911,10 +2911,9 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
} }
static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh, static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
struct neigh_table **tbl, void **dst, struct nlattr **tb,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct nlattr *tb[NDA_MAX + 1];
struct ndmsg *ndm; struct ndmsg *ndm;
int err, i; int err, i;
@ -2945,12 +2944,6 @@ static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
if (err < 0) if (err < 0)
return ERR_PTR(err); return ERR_PTR(err);
*tbl = neigh_find_table(ndm->ndm_family);
if (!*tbl) {
NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
return ERR_PTR(-EAFNOSUPPORT);
}
for (i = 0; i <= NDA_MAX; ++i) { for (i = 0; i <= NDA_MAX; ++i) {
switch (i) { switch (i) {
case NDA_DST: case NDA_DST:
@ -2958,12 +2951,6 @@ static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
NL_SET_ERR_ATTR_MISS(extack, NULL, NDA_DST); NL_SET_ERR_ATTR_MISS(extack, NULL, NDA_DST);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
return ERR_PTR(-EINVAL);
}
*dst = nla_data(tb[i]);
break; break;
default: default:
if (!tb[i]) if (!tb[i])
@ -3001,16 +2988,17 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
{ {
struct net *net = sock_net(in_skb->sk); struct net *net = sock_net(in_skb->sk);
u32 pid = NETLINK_CB(in_skb).portid; u32 pid = NETLINK_CB(in_skb).portid;
struct nlattr *tb[NDA_MAX + 1];
struct net_device *dev = NULL; struct net_device *dev = NULL;
struct neigh_table *tbl = NULL;
u32 seq = nlh->nlmsg_seq; u32 seq = nlh->nlmsg_seq;
struct neigh_table *tbl;
struct neighbour *neigh; struct neighbour *neigh;
struct sk_buff *skb; struct sk_buff *skb;
struct ndmsg *ndm; struct ndmsg *ndm;
void *dst = NULL; void *dst;
int err; int err;
ndm = neigh_valid_get_req(nlh, &tbl, &dst, extack); ndm = neigh_valid_get_req(nlh, tb, extack);
if (IS_ERR(ndm)) if (IS_ERR(ndm))
return PTR_ERR(ndm); return PTR_ERR(ndm);
@ -3021,6 +3009,21 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
if (!skb) if (!skb)
return -ENOBUFS; return -ENOBUFS;
tbl = neigh_find_table(ndm->ndm_family);
if (!tbl) {
NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
err = -EAFNOSUPPORT;
goto err_free_skb;
}
if (nla_len(tb[NDA_DST]) != (int)tbl->key_len) {
NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
err = -EINVAL;
goto err_free_skb;
}
dst = nla_data(tb[NDA_DST]);
if (ndm->ndm_ifindex) { if (ndm->ndm_ifindex) {
dev = __dev_get_by_index(net, ndm->ndm_ifindex); dev = __dev_get_by_index(net, ndm->ndm_ifindex);
if (!dev) { if (!dev) {