mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
ipv6: fix fib6 walker UAF on seq stop
ipv6_route_iter_active() treats a walker in FWS_U at the table root as
already unlinked. fib6_del_route() can move a still-linked walker into
that same state when the current leaf is the last route at the root,
so ipv6_route_native_seq_stop() skips fib6_walker_unlink(). The seq
private object can then be freed while it remains on
net->ipv6.fib6_walkers. A later route deletion walks the dangling list
and uses the freed walker.
Use the list head as membership state and reinitialize it when
unlinking. Keep the existing w->node check so a never-started iterator
with a zeroed private object is not treated as linked.
The same stop helper is used by /proc/net/ipv6_route and by the BPF
ipv6_route iterator. The BPF show path only widens the race.
Fixes: 8d2ca1d7b5 ("ipv6: avoid high order memory allocations for /proc/net/ipv6_route")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Co-developed-by: Luxing Yin <root@tr0jan.top>
Signed-off-by: Luxing Yin <root@tr0jan.top>
Signed-off-by: Zihan Xi <zihanx@nebusec.ai>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/89699735763f6c297584d7c2ff106239cc1e8ce0.1788837093.git.zihanx@nebusec.ai
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
5e38d732ec
commit
19b4ed644d
|
|
@ -85,7 +85,7 @@ static void fib6_walker_link(struct net *net, struct fib6_walker *w)
|
|||
static void fib6_walker_unlink(struct net *net, struct fib6_walker *w)
|
||||
{
|
||||
write_lock_bh(&net->ipv6.fib6_walker_lock);
|
||||
list_del(&w->lh);
|
||||
list_del_init(&w->lh);
|
||||
write_unlock_bh(&net->ipv6.fib6_walker_lock);
|
||||
}
|
||||
|
||||
|
|
@ -2760,7 +2760,7 @@ static void *ipv6_route_seq_start(struct seq_file *seq, loff_t *pos)
|
|||
static bool ipv6_route_iter_active(struct ipv6_route_iter *iter)
|
||||
{
|
||||
struct fib6_walker *w = &iter->w;
|
||||
return w->node && !(w->state == FWS_U && w->node == w->root);
|
||||
return w->node && !list_empty(&w->lh);
|
||||
}
|
||||
|
||||
static void ipv6_route_native_seq_stop(struct seq_file *seq, void *v)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user