[NETLINK]: Return -EPROTONOSUPPORT in netlink_create() if no kernel socket is registered
This is necessary for dynamic number of netlink groups to make sure we know
the number of possible groups before bind() is called. With this change pure
userspace communication using unused netlink protocols becomes impossible.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 3c56b96..444ed22 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -102,6 +102,7 @@
struct hlist_head mc_list;
unsigned int nl_nonroot;
struct module *module;
+ int registered;
};
static struct netlink_table *nl_table;
@@ -343,11 +344,32 @@
.obj_size = sizeof(struct netlink_sock),
};
-static int netlink_create(struct socket *sock, int protocol)
+static int __netlink_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct netlink_sock *nlk;
- struct module *module;
+
+ sock->ops = &netlink_ops;
+
+ sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1);
+ if (!sk)
+ return -ENOMEM;
+
+ sock_init_data(sock, sk);
+
+ nlk = nlk_sk(sk);
+ spin_lock_init(&nlk->cb_lock);
+ init_waitqueue_head(&nlk->wait);
+
+ sk->sk_destruct = netlink_sock_destruct;
+ sk->sk_protocol = protocol;
+ return 0;
+}
+
+static int netlink_create(struct socket *sock, int protocol)
+{
+ struct module *module = NULL;
+ int err = 0;
sock->state = SS_UNCONNECTED;
@@ -358,41 +380,33 @@
return -EPROTONOSUPPORT;
netlink_lock_table();
- if (!nl_table[protocol].hash.entries) {
#ifdef CONFIG_KMOD
- /* We do 'best effort'. If we find a matching module,
- * it is loaded. If not, we don't return an error to
- * allow pure userspace<->userspace communication. -HW
- */
+ if (!nl_table[protocol].registered) {
netlink_unlock_table();
request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol);
netlink_lock_table();
-#endif
}
- module = nl_table[protocol].module;
- if (!try_module_get(module))
- module = NULL;
+#endif
+ if (nl_table[protocol].registered &&
+ try_module_get(nl_table[protocol].module))
+ module = nl_table[protocol].module;
+ else
+ err = -EPROTONOSUPPORT;
netlink_unlock_table();
- sock->ops = &netlink_ops;
+ if (err)
+ goto out;
- sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1);
- if (!sk) {
- module_put(module);
- return -ENOMEM;
- }
+ if ((err = __netlink_create(sock, protocol) < 0))
+ goto out_module;
- sock_init_data(sock, sk);
+ nlk_sk(sock->sk)->module = module;
+out:
+ return err;
- nlk = nlk_sk(sk);
-
- nlk->module = module;
- spin_lock_init(&nlk->cb_lock);
- init_waitqueue_head(&nlk->wait);
- sk->sk_destruct = netlink_sock_destruct;
-
- sk->sk_protocol = protocol;
- return 0;
+out_module:
+ module_put(module);
+ goto out;
}
static int netlink_release(struct socket *sock)
@@ -437,6 +451,7 @@
if (nlk->flags & NETLINK_KERNEL_SOCKET) {
netlink_table_grab();
nl_table[sk->sk_protocol].module = NULL;
+ nl_table[sk->sk_protocol].registered = 0;
netlink_table_ungrab();
}
@@ -1082,7 +1097,7 @@
if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
return NULL;
- if (netlink_create(sock, unit) < 0)
+ if (__netlink_create(sock, unit) < 0)
goto out_sock_release;
sk = sock->sk;
@@ -1098,6 +1113,7 @@
netlink_table_grab();
nl_table[unit].module = module;
+ nl_table[unit].registered = 1;
netlink_table_ungrab();
return sk;