ipv6: fix error path of inet6_init()
Subsystems (2)
cover ipv6: fix error path of inet6_init()
The error path of inet6_init() can trigger multiple kernel panics, mostly due to wrong ordering of cleanups. This series fixes those issues.
Sabrina Dubroca (3):
ipv6: fix cleanup ordering for ip6_mr failure
ipv6: fix cleanup ordering for pingv6 registration
net: rtnl: return early from rtnl_unregister_all when protocol isn't
registered
net/core/rtnetlink.c | 4 ++++ net/ipv6/af_inet6.c | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-)
Signature · 1 line
2.18.0
PATCH 1/3 ipv6: fix cleanup ordering for ip6_mr failure
Commit 15e668070a64 ("ipv6: reorder icmpv6_init() and ip6_mr_init()") moved the cleanup label for ipmr_fail, but should have changed the contents of the cleanup labels as well. Now we can end up cleaning up icmpv6 even though it hasn't been initialized (jump to icmp_fail or ipmr_fail).
Simply undo things in the reverse order of their initialization.
Example of panic (triggered by faking a failure of icmpv6_init):
kasan: GPF could be caused by NULL-ptr deref or user memory access
general protection fault: 0000 [#1] PREEMPT SMP KASAN PTI
[...]
RIP: 0010:__list_del_entry_valid+0x79/0x160
[...]
Call Trace:
? lock_release+0x8a0/0x8a0
unregister_pernet_operations+0xd4/0x560
? ops_free_list+0x480/0x480
? down_write+0x91/0x130
? unregister_pernet_subsys+0x15/0x30
? down_read+0x1b0/0x1b0
? up_read+0x110/0x110
? kmem_cache_create_usercopy+0x1b4/0x240
unregister_pernet_subsys+0x1d/0x30
icmpv6_cleanup+0x1d/0x30
inet6_init+0x1b5/0x23f--- net/ipv6/af_inet6.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/ipv6/af_inet6.c +3 -3
@@ -1113,11 +1113,11 @@ static int __init inet6_init(void) igmp_fail:ndisc_cleanup (); ndisc_fail: -ip6_mr_cleanup (); +icmpv6_cleanup (); icmp_fail: -unregister_pernet_subsys (&inet6_net_ops); +ip6_mr_cleanup (); ipmr_fail: -icmpv6_cleanup (); +unregister_pernet_subsys (&inet6_net_ops); register_pernet_fail:sock_unregister (PF_INET6 );rtnl_unregister_all (PF_INET6 );
Signature · 1 line
2.18.0
PATCH 2/3 ipv6: fix cleanup ordering for pingv6 registration
In reply to Sabrina DubrocaCommit 6d0bfe226116 ("net: ipv6: Add IPv6 support to the ping socket.") contains an error in the cleanup path of inet6_init(): when proto_register(&pingv6_prot, 1) fails, we try to unregister &pingv6_prot. When rawv6_init() fails, we skip unregistering &pingv6_prot.
Example of panic (triggered by faking a failure of
proto_register(&pingv6_prot, 1)):
general protection fault: 0000 [#1] PREEMPT SMP KASAN PTI
[...]
RIP: 0010:__list_del_entry_valid+0x79/0x160
[...]
Call Trace:
proto_unregister+0xbb/0x550
? trace_preempt_on+0x6f0/0x6f0
? sock_no_shutdown+0x10/0x10
inet6_init+0x153/0x1b8--- net/ipv6/af_inet6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ipv6/af_inet6.c +2 -2
@@ -938,14 +938,14 @@ static int __init inet6_init(void) err =proto_register (&pingv6_prot,1 );if (err) - goto out_unregister_ping_proto; + goto out_unregister_raw_proto;/* We MUST register RAW sockets before we create the ICMP6, * IGMP6, or NDISC control sockets. */ err =rawv6_init ();if (err) - goto out_unregister_raw_proto; + goto out_unregister_ping_proto;/* Register the family here so that the init calls below will * be able to create sockets. (?? is this dangerous ??)
Signature · 1 line
2.18.0
PATCH 3/3 net: rtnl: return early from rtnl_unregister_all when protocol isn't registered
In reply to Sabrina Dubrocartnl_unregister_all(PF_INET6) gets called from inet6_init in cases when no handler has been registered for PF_INET6 yet, for example if ip6_mr_init() fails. Abort and avoid a NULL pointer deref in that case.
Example of panic (triggered by faking a failure of
register_pernet_subsys):
general protection fault: 0000 [#1] PREEMPT SMP KASAN PTI
[...]
RIP: 0010:rtnl_unregister_all+0x17e/0x2a0
[...]
Call Trace:
? rtnetlink_net_init+0x250/0x250
? sock_unregister+0x103/0x160
? kernel_getsockopt+0x200/0x200
inet6_init+0x197/0x20d--- net/core/rtnetlink.c | 4 ++++ 1 file changed, 4 insertions(+)
net/core/rtnetlink.c +4 -0
@@ -324,6 +324,10 @@ void rtnl_unregister_all(int protocol)rtnl_lock (); tab = rtnl_msg_handlers[protocol]; +if (!tab) { +rtnl_unlock (); +return ; + }RCU_INIT_POINTER (rtnl_msg_handlers[protocol],NULL );for (msgindex =0 ; msgindex <RTM_NR_MSGTYPES ; msgindex++) { link = tab[msgindex];
Signature · 1 line
2.18.0
----- Original Message -----
Quoted 10 lines
The error path of
inet6_init()can trigger multiple kernel panics, mostly due to wrong ordering of cleanups. This series fixes those issues.Sabrina Dubroca (3):
ipv6: fix cleanup ordering forip6_mrfailure
ipv6: fix cleanup ordering for pingv6 registration
net: rtnl: return early fromrtnl_unregister_allwhen protocol isn't
registered
Quoted 8 lines
net/core/rtnetlink.c | 4 ++++ net/ipv6/af_inet6.c | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-)--
2.18.0
Series Reviewed-by: Xin Long <[email protected]>
David Miller
maintainerFrom: Sabrina Dubroca <[email protected]>
Date: Tue, 28 Aug 2018 13:40:50 +0200
Quoted 3 lines
The error path of
inet6_init()can trigger multiple kernel panics, mostly due to wrong ordering of cleanups. This series fixes those issues.
Series applied, thank you.