Commit ab33a171 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[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: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ac6d439d
...@@ -102,6 +102,7 @@ struct netlink_table { ...@@ -102,6 +102,7 @@ struct netlink_table {
struct hlist_head mc_list; struct hlist_head mc_list;
unsigned int nl_nonroot; unsigned int nl_nonroot;
struct module *module; struct module *module;
int registered;
}; };
static struct netlink_table *nl_table; static struct netlink_table *nl_table;
...@@ -343,11 +344,32 @@ static struct proto netlink_proto = { ...@@ -343,11 +344,32 @@ static struct proto netlink_proto = {
.obj_size = sizeof(struct netlink_sock), .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 sock *sk;
struct netlink_sock *nlk; 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; sock->state = SS_UNCONNECTED;
...@@ -358,41 +380,33 @@ static int netlink_create(struct socket *sock, int protocol) ...@@ -358,41 +380,33 @@ static int netlink_create(struct socket *sock, int protocol)
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
netlink_lock_table(); netlink_lock_table();
if (!nl_table[protocol].hash.entries) {
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
/* We do 'best effort'. If we find a matching module, if (!nl_table[protocol].registered) {
* it is loaded. If not, we don't return an error to
* allow pure userspace<->userspace communication. -HW
*/
netlink_unlock_table(); netlink_unlock_table();
request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol);
netlink_lock_table(); netlink_lock_table();
#endif
} }
module = nl_table[protocol].module; #endif
if (!try_module_get(module)) if (nl_table[protocol].registered &&
module = NULL; try_module_get(nl_table[protocol].module))
module = nl_table[protocol].module;
else
err = -EPROTONOSUPPORT;
netlink_unlock_table(); 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;
}
sock_init_data(sock, sk);
nlk = nlk_sk(sk); if ((err = __netlink_create(sock, protocol) < 0))
goto out_module;
nlk->module = module; nlk_sk(sock->sk)->module = module;
spin_lock_init(&nlk->cb_lock); out:
init_waitqueue_head(&nlk->wait); return err;
sk->sk_destruct = netlink_sock_destruct;
sk->sk_protocol = protocol; out_module:
return 0; module_put(module);
goto out;
} }
static int netlink_release(struct socket *sock) static int netlink_release(struct socket *sock)
...@@ -437,6 +451,7 @@ static int netlink_release(struct socket *sock) ...@@ -437,6 +451,7 @@ static int netlink_release(struct socket *sock)
if (nlk->flags & NETLINK_KERNEL_SOCKET) { if (nlk->flags & NETLINK_KERNEL_SOCKET) {
netlink_table_grab(); netlink_table_grab();
nl_table[sk->sk_protocol].module = NULL; nl_table[sk->sk_protocol].module = NULL;
nl_table[sk->sk_protocol].registered = 0;
netlink_table_ungrab(); netlink_table_ungrab();
} }
...@@ -1082,7 +1097,7 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct ...@@ -1082,7 +1097,7 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct
if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
return NULL; return NULL;
if (netlink_create(sock, unit) < 0) if (__netlink_create(sock, unit) < 0)
goto out_sock_release; goto out_sock_release;
sk = sock->sk; sk = sock->sk;
...@@ -1098,6 +1113,7 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct ...@@ -1098,6 +1113,7 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct
netlink_table_grab(); netlink_table_grab();
nl_table[unit].module = module; nl_table[unit].module = module;
nl_table[unit].registered = 1;
netlink_table_ungrab(); netlink_table_ungrab();
return sk; return sk;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment