Skip to content

Commit 7d9b1b5

Browse files
edumazetdavem330
authored andcommitted
ip6mr: fix use-after-free in ip6mr_sk_done()
Apparently addrconf_exit_net() is called before igmp6_net_exit() and ndisc_net_exit() at netns dismantle time: net_namespace: call ip6table_mangle_net_exit() net_namespace: call ip6_tables_net_exit() net_namespace: call ipv6_sysctl_net_exit() net_namespace: call ioam6_net_exit() net_namespace: call seg6_net_exit() net_namespace: call ping_v6_proc_exit_net() net_namespace: call tcpv6_net_exit() ip6mr_sk_done sk=ffffa354c78a74c0 net_namespace: call ipv6_frags_exit_net() net_namespace: call addrconf_exit_net() net_namespace: call ip6addrlbl_net_exit() net_namespace: call ip6_flowlabel_net_exit() net_namespace: call ip6_route_net_exit_late() net_namespace: call fib6_rules_net_exit() net_namespace: call xfrm6_net_exit() net_namespace: call fib6_net_exit() net_namespace: call ip6_route_net_exit() net_namespace: call ipv6_inetpeer_exit() net_namespace: call if6_proc_net_exit() net_namespace: call ipv6_proc_exit_net() net_namespace: call udplite6_proc_exit_net() net_namespace: call raw6_exit_net() net_namespace: call igmp6_net_exit() ip6mr_sk_done sk=ffffa35472b2a180 ip6mr_sk_done sk=ffffa354c78a7980 net_namespace: call ndisc_net_exit() ip6mr_sk_done sk=ffffa35472b2ab00 net_namespace: call ip6mr_net_exit() net_namespace: call inet6_net_exit() This was fine because ip6mr_sk_done() would not reach the point decreasing net->ipv6.devconf_all->mc_forwarding until my patch in ip6mr_sk_done(). To fix this without changing struct pernet_operations ordering, we can clear net->ipv6.devconf_dflt and net->ipv6.devconf_all when they are freed from addrconf_exit_net() BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:71 [inline] BUG: KASAN: use-after-free in atomic_read include/linux/atomic/atomic-instrumented.h:27 [inline] BUG: KASAN: use-after-free in ip6mr_sk_done+0x11b/0x410 net/ipv6/ip6mr.c:1578 Read of size 4 at addr ffff88801ff08688 by task kworker/u4:4/963 CPU: 0 PID: 963 Comm: kworker/u4:4 Not tainted 5.17.0-rc2-syzkaller-00650-g5a8fb33e5305 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: netns cleanup_net Call Trace: <TASK> __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 print_address_description.constprop.0.cold+0x8d/0x336 mm/kasan/report.c:255 __kasan_report mm/kasan/report.c:442 [inline] kasan_report.cold+0x83/0xdf mm/kasan/report.c:459 check_region_inline mm/kasan/generic.c:183 [inline] kasan_check_range+0x13d/0x180 mm/kasan/generic.c:189 instrument_atomic_read include/linux/instrumented.h:71 [inline] atomic_read include/linux/atomic/atomic-instrumented.h:27 [inline] ip6mr_sk_done+0x11b/0x410 net/ipv6/ip6mr.c:1578 rawv6_close+0x58/0x80 net/ipv6/raw.c:1201 inet_release+0x12e/0x280 net/ipv4/af_inet.c:428 inet6_release+0x4c/0x70 net/ipv6/af_inet6.c:478 __sock_release net/socket.c:650 [inline] sock_release+0x87/0x1b0 net/socket.c:678 inet_ctl_sock_destroy include/net/inet_common.h:65 [inline] igmp6_net_exit+0x6b/0x170 net/ipv6/mcast.c:3173 ops_exit_list+0xb0/0x170 net/core/net_namespace.c:168 cleanup_net+0x4ea/0xb00 net/core/net_namespace.c:600 process_one_work+0x9ac/0x1650 kernel/workqueue.c:2307 worker_thread+0x657/0x1110 kernel/workqueue.c:2454 kthread+0x2e9/0x3a0 kernel/kthread.c:377 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295 </TASK> Fixes: f2f2325 ("ip6mr: ip6mr_sk_done() can exit early in common cases") Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: syzbot <syzkaller@googlegroups.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0812beb commit 7d9b1b5

File tree

2 files changed

+7
-3
lines changed

2 files changed

+7
-3
lines changed

net/ipv6/addrconf.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7184,7 +7184,9 @@ static void __net_exit addrconf_exit_net(struct net *net)
71847184
NETCONFA_IFINDEX_ALL);
71857185
#endif
71867186
kfree(net->ipv6.devconf_dflt);
7187+
net->ipv6.devconf_dflt = NULL;
71877188
kfree(net->ipv6.devconf_all);
7189+
net->ipv6.devconf_all = NULL;
71887190
}
71897191

71907192
static struct pernet_operations addrconf_ops = {

net/ipv6/ip6mr.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,15 +1567,17 @@ static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
15671567

15681568
int ip6mr_sk_done(struct sock *sk)
15691569
{
1570-
int err = -EACCES;
15711570
struct net *net = sock_net(sk);
1571+
struct ipv6_devconf *devconf;
15721572
struct mr_table *mrt;
1573+
int err = -EACCES;
15731574

15741575
if (sk->sk_type != SOCK_RAW ||
15751576
inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
15761577
return err;
15771578

1578-
if (!atomic_read(&net->ipv6.devconf_all->mc_forwarding))
1579+
devconf = net->ipv6.devconf_all;
1580+
if (!devconf || !atomic_read(&devconf->mc_forwarding))
15791581
return err;
15801582

15811583
rtnl_lock();
@@ -1587,7 +1589,7 @@ int ip6mr_sk_done(struct sock *sk)
15871589
* so the RCU grace period before sk freeing
15881590
* is guaranteed by sk_destruct()
15891591
*/
1590-
atomic_dec(&net->ipv6.devconf_all->mc_forwarding);
1592+
atomic_dec(&devconf->mc_forwarding);
15911593
write_unlock_bh(&mrt_lock);
15921594
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
15931595
NETCONFA_MC_FORWARDING,

0 commit comments

Comments
 (0)