Skip to contentSkip to conversation

ipv6: fix error path of inet6_init()

PATCH In review Sabrina Dubroca 3 participants 6 messages Aug 28, 2018 – Aug 30, 2018

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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
Fixes 15e668070a64 ("ipv6: reorder icmpv6_init() and ip6_mr_init()")
---
 net/ipv6/af_inet6.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
net/ipv6/af_inet6.c +3 -3
index 673bba31eb18..e5da133c6932 100644
@@ -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
#2 lore raw

PATCH 2/3 ipv6: fix cleanup ordering for pingv6 registration

In reply to Sabrina Dubroca

Commit 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
Fixes 6d0bfe226116 ("net: ipv6: Add IPv6 support to the ping socket.")
---
 net/ipv6/af_inet6.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/ipv6/af_inet6.c +2 -2
index e5da133c6932..9a4261e50272 100644
@@ -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
#3 lore raw

PATCH 3/3 net: rtnl: return early from rtnl_unregister_all when protocol isn't registered

In reply to Sabrina Dubroca

rtnl_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
Fixes e2fddf5e96df ("[IPV6]: Make af_inet6 to check ip6_route_init return value.")
---
 net/core/rtnetlink.c | 4 ++++
 1 file changed, 4 insertions(+)
net/core/rtnetlink.c +4 -0
index 24431e578310..60c928894a78 100644
@@ -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
#4 lore raw
In reply to Sabrina Dubroca

----- 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 for ip6_mr failure
ipv6: fix cleanup ordering for pingv6 registration
net: rtnl: return early from rtnl_unregister_all when 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]>

maintainer
#5 lore raw
In reply to Sabrina Dubroca

From: 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.