aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2005-08-14 19:31:36 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 16:00:58 -0700
commitab33a1711cf60bfb562b1ab89ac9f23d1425e8b1 (patch)
treeabd497f5b7023ff748001d6ef182d74f882f1a07 /net/netlink
parent[NETLINK]: Convert netlink users to use group numbers instead of bitmasks (diff)
downloadlinux-dev-ab33a1711cf60bfb562b1ab89ac9f23d1425e8b1.tar.xz
linux-dev-ab33a1711cf60bfb562b1ab89ac9f23d1425e8b1.zip
[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>
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/af_netlink.c72
1 files changed, 44 insertions, 28 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 3c56b96b4a4b..444ed223ee43 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -102,6 +102,7 @@ struct netlink_table {
struct hlist_head mc_list;
unsigned int nl_nonroot;
struct module *module;
+ int registered;
};
static struct netlink_table *nl_table;
@@ -343,11 +344,32 @@ static struct proto netlink_proto = {
.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 @@ static int netlink_create(struct socket *sock, int protocol)
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;
-
- sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1);
- if (!sk) {
- module_put(module);
- return -ENOMEM;
- }
-
- sock_init_data(sock, sk);
+ if (err)
+ goto out;
- nlk = nlk_sk(sk);
+ if ((err = __netlink_create(sock, protocol) < 0))
+ goto out_module;
- nlk->module = module;
- spin_lock_init(&nlk->cb_lock);
- init_waitqueue_head(&nlk->wait);
- sk->sk_destruct = netlink_sock_destruct;
+ nlk_sk(sock->sk)->module = module;
+out:
+ return err;
- sk->sk_protocol = protocol;
- return 0;
+out_module:
+ module_put(module);
+ goto out;
}
static int netlink_release(struct socket *sock)
@@ -437,6 +451,7 @@ static int netlink_release(struct socket *sock)
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 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct
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_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct
netlink_table_grab();
nl_table[unit].module = module;
+ nl_table[unit].registered = 1;
netlink_table_ungrab();
return sk;