Loop index in neigh dump function is not updated correctly under some circumstances, this patch will fix it.
Fixes: 16660f0bd9 ("net: Add support for filtering neigh dump by device index") Fixes: 21fdd092ac ("net: Add support for filtering neigh dump by master device") Signed-off-by: Zhang Shengju <zhangshen...@cmss.chinamobile.com> --- net/core/neighbour.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 2ae929f..ce32e9c 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2256,6 +2256,16 @@ static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx) return false; } +static bool neigh_dump_filtered(struct net_device *dev, int filter_idx, + int filter_master_idx) +{ + if (neigh_ifindex_filtered(dev, filter_idx) || + neigh_master_filtered(dev, filter_master_idx)) + return true; + + return false; +} + static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, struct netlink_callback *cb) { @@ -2285,20 +2295,15 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, rcu_read_lock_bh(); nht = rcu_dereference_bh(tbl->nht); - for (h = s_h; h < (1 << nht->hash_shift); h++) { - if (h > s_h) - s_idx = 0; + for (h = s_h; h < (1 << nht->hash_shift); h++, s_idx = 0) { for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0; n != NULL; - n = rcu_dereference_bh(n->next)) { - if (!net_eq(dev_net(n->dev), net)) - continue; - if (neigh_ifindex_filtered(n->dev, filter_idx)) + n = rcu_dereference_bh(n->next), idx++) { + if (idx < s_idx || !net_eq(dev_net(n->dev), net)) continue; - if (neigh_master_filtered(n->dev, filter_master_idx)) + if (neigh_dump_filtered(n->dev, filter_idx, + filter_master_idx)) continue; - if (idx < s_idx) - goto next; if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWNEIGH, @@ -2306,8 +2311,6 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, rc = -1; goto out; } -next: - idx++; } } rc = skb->len; @@ -2328,14 +2331,10 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, read_lock_bh(&tbl->lock); - for (h = s_h; h <= PNEIGH_HASHMASK; h++) { - if (h > s_h) - s_idx = 0; - for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { - if (pneigh_net(n) != net) + for (h = s_h; h <= PNEIGH_HASHMASK; h++, s_idx = 0) { + for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next, idx++) { + if (idx < s_idx || pneigh_net(n) != net) continue; - if (idx < s_idx) - goto next; if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWNEIGH, @@ -2344,8 +2343,6 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, rc = -1; goto out; } - next: - idx++; } } -- 1.8.3.1