lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20221103090345.187989-1-chenzhongjin@huawei.com>
Date:   Thu, 3 Nov 2022 17:03:45 +0800
From:   Chen Zhongjin <chenzhongjin@...wei.com>
To:     <linux-kernel@...r.kernel.org>, <netdev@...r.kernel.org>
CC:     <davem@...emloft.net>, <yoshfuji@...ux-ipv6.org>,
        <dsahern@...nel.org>, <edumazet@...gle.com>, <kuba@...nel.org>,
        <pabeni@...hat.com>, <lorenzo@...gle.com>,
        <chenzhongjin@...wei.com>
Subject: [PATCH net] net: ping6: Fix possible leaked pernet namespace in pingv6_init()

When IPv6 module initializing in pingv6_init(), inet6_register_protosw()
is possible to fail but returns without any error cleanup.

This leaves wild ops in namespace list and when another module tries to
add or delete pernet namespace it triggers page fault.
Although IPv6 cannot be unloaded now, this error should still be handled
to avoid kernel panic during IPv6 initialization.

BUG: unable to handle page fault for address: fffffbfff80bab69
CPU: 0 PID: 434 Comm: modprobe
RIP: 0010:unregister_pernet_operations+0xc9/0x450
Call Trace:
 <TASK>
 unregister_pernet_subsys+0x31/0x3e
 nf_tables_module_exit+0x44/0x6a [nf_tables]
 __do_sys_delete_module.constprop.0+0x34f/0x5b0
 ...

Fix it by adding error handling in pingv6_init(), and add a helper
function pingv6_ops_unset to avoid duplicate code.

Fixes: d862e5461423 ("net: ipv6: Implement /proc/net/icmp6.")
Signed-off-by: Chen Zhongjin <chenzhongjin@...wei.com>
---
 net/ipv6/ping.c | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index 86c26e48d065..5df688dd5208 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -277,10 +277,21 @@ static struct pernet_operations ping_v6_net_ops = {
 };
 #endif
 
+static void pingv6_ops_unset(void)
+{
+	pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error;
+	pingv6_ops.ip6_datagram_recv_common_ctl = dummy_ip6_datagram_recv_ctl;
+	pingv6_ops.ip6_datagram_recv_specific_ctl = dummy_ip6_datagram_recv_ctl;
+	pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert;
+	pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error;
+	pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr;
+}
+
 int __init pingv6_init(void)
 {
+	int ret;
 #ifdef CONFIG_PROC_FS
-	int ret = register_pernet_subsys(&ping_v6_net_ops);
+	ret = register_pernet_subsys(&ping_v6_net_ops);
 	if (ret)
 		return ret;
 #endif
@@ -291,7 +302,15 @@ int __init pingv6_init(void)
 	pingv6_ops.icmpv6_err_convert = icmpv6_err_convert;
 	pingv6_ops.ipv6_icmp_error = ipv6_icmp_error;
 	pingv6_ops.ipv6_chk_addr = ipv6_chk_addr;
-	return inet6_register_protosw(&pingv6_protosw);
+
+	ret = inet6_register_protosw(&pingv6_protosw);
+	if (ret) {
+		pingv6_ops_unset();
+#ifdef CONFIG_PROC_FS
+		unregister_pernet_subsys(&ping_v6_net_ops);
+#endif
+	}
+	return ret;
 }
 
 /* This never gets called because it's not possible to unload the ipv6 module,
@@ -299,12 +318,7 @@ int __init pingv6_init(void)
  */
 void pingv6_exit(void)
 {
-	pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error;
-	pingv6_ops.ip6_datagram_recv_common_ctl = dummy_ip6_datagram_recv_ctl;
-	pingv6_ops.ip6_datagram_recv_specific_ctl = dummy_ip6_datagram_recv_ctl;
-	pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert;
-	pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error;
-	pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr;
+	pingv6_ops_unset();
 #ifdef CONFIG_PROC_FS
 	unregister_pernet_subsys(&ping_v6_net_ops);
 #endif
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ