6a8247
From b100598ffd55b71a99567555d7971d07e7b42ac3 Mon Sep 17 00:00:00 2001
6a8247
From: Guillaume Nault <g.nault@alphalink.fr>
6a8247
Date: Tue, 10 Apr 2018 21:01:13 +0200
6a8247
Subject: [PATCH 2/3] l2tp: fix race in duplicate tunnel detection
6a8247
Git-commit: f6cd651b056ffd3b4e8496afd44d4ed44bf69136
6a8247
Patch-mainline: v4.17-rc1
6a8247
References: bsc#1205711 CVE-2022-4129
6a8247
6a8247
We can't use l2tp_tunnel_find() to prevent l2tp_nl_cmd_tunnel_create()
6a8247
from creating a duplicate tunnel. A tunnel can be concurrently
6a8247
registered after l2tp_tunnel_find() returns. Therefore, searching for
6a8247
duplicates must be done at registration time.
6a8247
6a8247
Finally, remove l2tp_tunnel_find() entirely as it isn't use anywhere
6a8247
anymore.
6a8247
6a8247
Fixes: 309795f4bec2 ("l2tp: Add netlink control API for L2TP")
6a8247
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
6a8247
Signed-off-by: David S. Miller <davem@davemloft.net>
6a8247
Signed-off-by: Denis Kirjanov <denis.kirjanov@suse.com>
6a8247
---
6a8247
 net/l2tp/l2tp_core.c    | 35 ++++++++++++++---------------------
6a8247
 net/l2tp/l2tp_core.h    |  1 -
6a8247
 net/l2tp/l2tp_netlink.c |  6 ------
6a8247
 3 files changed, 14 insertions(+), 28 deletions(-)
6a8247
6a8247
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
6a8247
index b71becd4d522..c28cf5c0e80a 100644
6a8247
--- a/net/l2tp/l2tp_core.c
6a8247
+++ b/net/l2tp/l2tp_core.c
6a8247
@@ -334,26 +334,6 @@ int l2tp_session_register(struct l2tp_session *session,
6a8247
 }
6a8247
 EXPORT_SYMBOL_GPL(l2tp_session_register);
6a8247
 
6a8247
-/* Lookup a tunnel by id
6a8247
- */
6a8247
-struct l2tp_tunnel *l2tp_tunnel_find(const struct net *net, u32 tunnel_id)
6a8247
-{
6a8247
-	struct l2tp_tunnel *tunnel;
6a8247
-	struct l2tp_net *pn = l2tp_pernet(net);
6a8247
-
6a8247
-	rcu_read_lock_bh();
6a8247
-	list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
6a8247
-		if (tunnel->tunnel_id == tunnel_id) {
6a8247
-			rcu_read_unlock_bh();
6a8247
-			return tunnel;
6a8247
-		}
6a8247
-	}
6a8247
-	rcu_read_unlock_bh();
6a8247
-
6a8247
-	return NULL;
6a8247
-}
6a8247
-EXPORT_SYMBOL_GPL(l2tp_tunnel_find);
6a8247
-
6a8247
 struct l2tp_tunnel *l2tp_tunnel_find_nth(const struct net *net, int nth)
6a8247
 {
6a8247
 	struct l2tp_net *pn = l2tp_pernet(net);
6a8247
@@ -1513,6 +1493,7 @@ static int l2tp_validate_socket(const struct sock *sk, const struct net *net,
6a8247
 int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
6a8247
 			 struct l2tp_tunnel_cfg *cfg)
6a8247
 {
6a8247
+	struct l2tp_tunnel *tunnel_walk;
6a8247
 	struct l2tp_net *pn;
6a8247
 	struct socket *sock;
6a8247
 	struct sock *sk;
6a8247
@@ -1541,7 +1522,16 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
6a8247
 	tunnel->l2tp_net = net;
6a8247
 
6a8247
 	pn = l2tp_pernet(net);
6a8247
+
6a8247
 	spin_lock_bh(&pn->l2tp_tunnel_list_lock);
6a8247
+	list_for_each_entry(tunnel_walk, &pn->l2tp_tunnel_list, list) {
6a8247
+		if (tunnel_walk->tunnel_id == tunnel->tunnel_id) {
6a8247
+			spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
6a8247
+
6a8247
+			ret = -EEXIST;
6a8247
+			goto err_sock;
6a8247
+		}
6a8247
+	}
6a8247
 	list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list);
6a8247
 	spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
6a8247
 
6a8247
@@ -1570,7 +1560,10 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
6a8247
 	return 0;
6a8247
 
6a8247
 err_sock:
6a8247
-	sockfd_put(sock);
6a8247
+	if (tunnel->fd < 0)
6a8247
+		sock_release(sock);
6a8247
+	else
6a8247
+		sockfd_put(sock);
6a8247
 err:
6a8247
 	return ret;
6a8247
 }
6a8247
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
6a8247
index 076f96f3772b..309ee6e70871 100644
6a8247
--- a/net/l2tp/l2tp_core.h
6a8247
+++ b/net/l2tp/l2tp_core.h
6a8247
@@ -251,7 +251,6 @@ struct l2tp_session *l2tp_session_get(const struct net *net,
6a8247
 struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth);
6a8247
 struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
6a8247
 						const char *ifname);
6a8247
-struct l2tp_tunnel *l2tp_tunnel_find(const struct net *net, u32 tunnel_id);
6a8247
 struct l2tp_tunnel *l2tp_tunnel_find_nth(const struct net *net, int nth);
6a8247
 
6a8247
 int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id,
6a8247
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
6a8247
index bd12e695fae8..ad9170044f67 100644
6a8247
--- a/net/l2tp/l2tp_netlink.c
6a8247
+++ b/net/l2tp/l2tp_netlink.c
6a8247
@@ -236,12 +236,6 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
6a8247
 	if (info->attrs[L2TP_ATTR_DEBUG])
6a8247
 		cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
6a8247
 
6a8247
-	tunnel = l2tp_tunnel_find(net, tunnel_id);
6a8247
-	if (tunnel != NULL) {
6a8247
-		ret = -EEXIST;
6a8247
-		goto out;
6a8247
-	}
6a8247
-
6a8247
 	ret = -EINVAL;
6a8247
 	switch (cfg.encap) {
6a8247
 	case L2TP_ENCAPTYPE_UDP:
6a8247
-- 
6a8247
2.16.4
6a8247