@@ -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);
@@ -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);
@@ -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);
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@amazon.com> --- include/linux/net.h | 6 ++++++ net/core/sock.c | 2 +- net/socket.c | 11 ++++++----- 3 files changed, 13 insertions(+), 6 deletions(-)