[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240227011041.97375-4-kuniyu@amazon.com>
Date: Mon, 26 Feb 2024 17:10:39 -0800
From: Kuniyuki Iwashima <kuniyu@...zon.com>
To: "David S. Miller" <davem@...emloft.net>, Eric Dumazet
<edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>, Paolo Abeni
<pabeni@...hat.com>, Allison Henderson <allison.henderson@...cle.com>
CC: Kuniyuki Iwashima <kuniyu@...zon.com>, Kuniyuki Iwashima
<kuni1840@...il.com>, <netdev@...r.kernel.org>, <linux-rdma@...r.kernel.org>,
<rds-devel@....oracle.com>
Subject: [PATCH v2 net 3/5] net: Convert @kern of __sock_create() to enum.
Historically, syzbot has reported many use-after-free of struct
net by kernel sockets.
In most cases, the root cause was a timer kicked by a kernel socket
which does not hold netns refcount nor clean it up during netns
dismantle.
This patch converts the @kern argument of __sock_create() to enum
so that we can pass SOCKET_KERN_NET_REF and later sk_alloc() can
hold refcount of net for kernel sockets.
We pass !!kern to security_socket(_post)?_create() but kern as is
to pf->create() because 3 functions (atalk_create(), inet_create(),
inet6_create()) use it for the following check:
if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
The conversion for rest of the callers of __sock_create() and
sk_alloc() will be completed in net-next.git as the change is
too large to backport.
Signed-off-by: Kuniyuki Iwashima <kuniyu@...zon.com>
---
include/linux/net.h | 6 ++++++
net/core/sock.c | 2 +-
net/socket.c | 11 ++++++-----
3 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/include/linux/net.h b/include/linux/net.h
index c9b4a63791a4..62ef0954be75 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -245,6 +245,12 @@ enum {
SOCK_WAKE_URG,
};
+enum socket_user {
+ SOCKET_USER,
+ SOCKET_KERN,
+ SOCKET_KERN_NET_REF,
+};
+
int sock_wake_async(struct socket_wq *sk_wq, int how, int band);
int sock_register(const struct net_proto_family *fam);
void sock_unregister(int family);
diff --git a/net/core/sock.c b/net/core/sock.c
index 5e78798456fd..6f417cdbcf50 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2138,7 +2138,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
sk->sk_prot = sk->sk_prot_creator = prot;
sk->sk_kern_sock = kern;
sock_lock_init(sk);
- sk->sk_net_refcnt = kern ? 0 : 1;
+ sk->sk_net_refcnt = kern != SOCKET_KERN;
if (likely(sk->sk_net_refcnt)) {
get_net_track(net, &sk->ns_tracker, priority);
sock_inuse_add(net, 1);
diff --git a/net/socket.c b/net/socket.c
index ed3df2f749bf..f5ec613d9e3b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1489,7 +1489,7 @@ EXPORT_SYMBOL(sock_wake_async);
* @type: communication type (SOCK_STREAM, ...)
* @protocol: protocol (0, ...)
* @res: new socket
- * @kern: boolean for kernel space sockets
+ * @kern: enum for kernel space sockets
*
* Creates a new socket and assigns it to @res, passing through LSM.
* Returns 0 or an error. On failure @res is set to %NULL. @kern must
@@ -1523,7 +1523,7 @@ int __sock_create(struct net *net, int family, int type, int protocol,
family = PF_PACKET;
}
- err = security_socket_create(family, type, protocol, kern);
+ err = security_socket_create(family, type, protocol, !!kern);
if (err)
return err;
@@ -1584,7 +1584,7 @@ int __sock_create(struct net *net, int family, int type, int protocol,
* module can have its refcnt decremented
*/
module_put(pf->owner);
- err = security_socket_post_create(sock, family, type, protocol, kern);
+ err = security_socket_post_create(sock, family, type, protocol, !!kern);
if (err)
goto out_sock_release;
*res = sock;
@@ -1619,7 +1619,8 @@ EXPORT_SYMBOL(__sock_create);
int sock_create(int family, int type, int protocol, struct socket **res)
{
- return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
+ return __sock_create(current->nsproxy->net_ns, family, type, protocol,
+ res, SOCKET_USER);
}
EXPORT_SYMBOL(sock_create);
@@ -1637,7 +1638,7 @@ EXPORT_SYMBOL(sock_create);
int sock_create_kern(struct net *net, int family, int type, int protocol, struct socket **res)
{
- return __sock_create(net, family, type, protocol, res, 1);
+ return __sock_create(net, family, type, protocol, res, SOCKET_KERN);
}
EXPORT_SYMBOL(sock_create_kern);
--
2.30.2
Powered by blists - more mailing lists