diff options
author | Harald Welte <laforge@netfilter.org> | 2005-08-09 22:40:55 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:35:08 -0400 |
commit | 4fdb3bb723db469717c6d38fda667d8b0fa86ebd (patch) | |
tree | 43d82e717922e6319cf8a8f9dc5ee902c651b491 | |
parent | 020b4c12dbe3868d792a01d7c1470cd837abe10f (diff) |
[NETLINK]: Add properly module refcounting for kernel netlink sockets.
- Remove bogus code for compiling netlink as module
- Add module refcounting support for modules implementing a netlink
protocol
- Add support for autoloading modules that implement a netlink protocol
as soon as someone opens a socket for that protocol
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/w1/w1_int.c | 4 | ||||
-rw-r--r-- | include/linux/net.h | 3 | ||||
-rw-r--r-- | include/linux/netlink.h | 2 | ||||
-rw-r--r-- | kernel/audit.c | 3 | ||||
-rw-r--r-- | lib/kobject_uevent.c | 3 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_ulog.c | 2 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 2 | ||||
-rw-r--r-- | net/decnet/netfilter/dn_rtmsg.c | 4 | ||||
-rw-r--r-- | net/ipv4/fib_frontend.c | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_ULOG.c | 3 | ||||
-rw-r--r-- | net/ipv4/tcp_diag.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 2 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 5 | ||||
-rw-r--r-- | net/netlink/af_netlink.c | 108 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 4 | ||||
-rw-r--r-- | security/selinux/netlink.c | 2 |
17 files changed, 119 insertions, 36 deletions
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index b5a5e04b6d37..8809788dac26 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -88,7 +88,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
88 | 88 | ||
89 | dev->groups = 23; | 89 | dev->groups = 23; |
90 | dev->seq = 1; | 90 | dev->seq = 1; |
91 | dev->nls = netlink_kernel_create(NETLINK_W1, NULL); | 91 | dev->nls = netlink_kernel_create(NETLINK_W1, NULL, THIS_MODULE); |
92 | if (!dev->nls) { | 92 | if (!dev->nls) { |
93 | printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n", | 93 | printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n", |
94 | NETLINK_NFLOG, dev->dev.bus_id); | 94 | NETLINK_NFLOG, dev->dev.bus_id); |
@@ -225,3 +225,5 @@ void w1_remove_master_device(struct w1_bus_master *bm) | |||
225 | 225 | ||
226 | EXPORT_SYMBOL(w1_add_master_device); | 226 | EXPORT_SYMBOL(w1_add_master_device); |
227 | EXPORT_SYMBOL(w1_remove_master_device); | 227 | EXPORT_SYMBOL(w1_remove_master_device); |
228 | |||
229 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_W1); | ||
diff --git a/include/linux/net.h b/include/linux/net.h index 20cb226b2268..39906619b9d7 100644 --- a/include/linux/net.h +++ b/include/linux/net.h | |||
@@ -282,5 +282,8 @@ static struct proto_ops name##_ops = { \ | |||
282 | #define MODULE_ALIAS_NETPROTO(proto) \ | 282 | #define MODULE_ALIAS_NETPROTO(proto) \ |
283 | MODULE_ALIAS("net-pf-" __stringify(proto)) | 283 | MODULE_ALIAS("net-pf-" __stringify(proto)) |
284 | 284 | ||
285 | #define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \ | ||
286 | MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto)) | ||
287 | |||
285 | #endif /* __KERNEL__ */ | 288 | #endif /* __KERNEL__ */ |
286 | #endif /* _LINUX_NET_H */ | 289 | #endif /* _LINUX_NET_H */ |
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 6552b71bfa73..1c50fea8995b 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h | |||
@@ -117,7 +117,7 @@ struct netlink_skb_parms | |||
117 | #define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds) | 117 | #define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds) |
118 | 118 | ||
119 | 119 | ||
120 | extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)); | 120 | extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct module *module); |
121 | extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); | 121 | extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); |
122 | extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); | 122 | extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); |
123 | extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, | 123 | extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, |
diff --git a/kernel/audit.c b/kernel/audit.c index ef35166fdc29..ed4019563d56 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -514,7 +514,8 @@ static int __init audit_init(void) | |||
514 | { | 514 | { |
515 | printk(KERN_INFO "audit: initializing netlink socket (%s)\n", | 515 | printk(KERN_INFO "audit: initializing netlink socket (%s)\n", |
516 | audit_default ? "enabled" : "disabled"); | 516 | audit_default ? "enabled" : "disabled"); |
517 | audit_sock = netlink_kernel_create(NETLINK_AUDIT, audit_receive); | 517 | audit_sock = netlink_kernel_create(NETLINK_AUDIT, audit_receive, |
518 | THIS_MODULE); | ||
518 | if (!audit_sock) | 519 | if (!audit_sock) |
519 | audit_panic("cannot initialize netlink socket"); | 520 | audit_panic("cannot initialize netlink socket"); |
520 | 521 | ||
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 8e49d21057e4..88f4d746aa05 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c | |||
@@ -153,7 +153,8 @@ EXPORT_SYMBOL_GPL(kobject_uevent_atomic); | |||
153 | 153 | ||
154 | static int __init kobject_uevent_init(void) | 154 | static int __init kobject_uevent_init(void) |
155 | { | 155 | { |
156 | uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, NULL); | 156 | uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, NULL, |
157 | THIS_MODULE); | ||
157 | 158 | ||
158 | if (!uevent_sock) { | 159 | if (!uevent_sock) { |
159 | printk(KERN_ERR | 160 | printk(KERN_ERR |
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index 01af4fcef26d..561d75c8ed5a 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c | |||
@@ -258,7 +258,7 @@ static int __init init(void) | |||
258 | spin_lock_init(&ulog_buffers[i].lock); | 258 | spin_lock_init(&ulog_buffers[i].lock); |
259 | } | 259 | } |
260 | 260 | ||
261 | ebtulognl = netlink_kernel_create(NETLINK_NFLOG, NULL); | 261 | ebtulognl = netlink_kernel_create(NETLINK_NFLOG, NULL, THIS_MODULE); |
262 | if (!ebtulognl) | 262 | if (!ebtulognl) |
263 | ret = -ENOMEM; | 263 | ret = -ENOMEM; |
264 | else if ((ret = ebt_register_watcher(&ulog))) | 264 | else if ((ret = ebt_register_watcher(&ulog))) |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4b1bb30e6381..9b3c61f1a37d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -708,7 +708,7 @@ void __init rtnetlink_init(void) | |||
708 | if (!rta_buf) | 708 | if (!rta_buf) |
709 | panic("rtnetlink_init: cannot allocate rta_buf\n"); | 709 | panic("rtnetlink_init: cannot allocate rta_buf\n"); |
710 | 710 | ||
711 | rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv); | 711 | rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv, THIS_MODULE); |
712 | if (rtnl == NULL) | 712 | if (rtnl == NULL) |
713 | panic("rtnetlink_init: cannot initialize rtnetlink\n"); | 713 | panic("rtnetlink_init: cannot initialize rtnetlink\n"); |
714 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); | 714 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); |
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index 284a9998e53d..3068fddb2da3 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c | |||
@@ -138,7 +138,8 @@ static int __init init(void) | |||
138 | { | 138 | { |
139 | int rv = 0; | 139 | int rv = 0; |
140 | 140 | ||
141 | dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk); | 141 | dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk, |
142 | THIS_MODULE); | ||
142 | if (dnrmg == NULL) { | 143 | if (dnrmg == NULL) { |
143 | printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket"); | 144 | printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket"); |
144 | return -ENOMEM; | 145 | return -ENOMEM; |
@@ -162,6 +163,7 @@ static void __exit fini(void) | |||
162 | MODULE_DESCRIPTION("DECnet Routing Message Grabulator"); | 163 | MODULE_DESCRIPTION("DECnet Routing Message Grabulator"); |
163 | MODULE_AUTHOR("Steven Whitehouse <steve@chygwyn.com>"); | 164 | MODULE_AUTHOR("Steven Whitehouse <steve@chygwyn.com>"); |
164 | MODULE_LICENSE("GPL"); | 165 | MODULE_LICENSE("GPL"); |
166 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_DNRTMSG); | ||
165 | 167 | ||
166 | module_init(init); | 168 | module_init(init); |
167 | module_exit(fini); | 169 | module_exit(fini); |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index e5722084239b..b5e2f1550c91 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -567,7 +567,7 @@ static void nl_fib_input(struct sock *sk, int len) | |||
567 | 567 | ||
568 | static void nl_fib_lookup_init(void) | 568 | static void nl_fib_lookup_init(void) |
569 | { | 569 | { |
570 | netlink_kernel_create(NETLINK_FIB_LOOKUP, nl_fib_input); | 570 | netlink_kernel_create(NETLINK_FIB_LOOKUP, nl_fib_input, THIS_MODULE); |
571 | } | 571 | } |
572 | 572 | ||
573 | static void fib_disable_ip(struct net_device *dev, int force) | 573 | static void fib_disable_ip(struct net_device *dev, int force) |
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index ae975ac59c6a..b237f7fcad92 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
@@ -692,7 +692,8 @@ init_or_cleanup(int init) | |||
692 | goto cleanup; | 692 | goto cleanup; |
693 | 693 | ||
694 | netlink_register_notifier(&ipq_nl_notifier); | 694 | netlink_register_notifier(&ipq_nl_notifier); |
695 | ipqnl = netlink_kernel_create(NETLINK_FIREWALL, ipq_rcv_sk); | 695 | ipqnl = netlink_kernel_create(NETLINK_FIREWALL, ipq_rcv_sk, |
696 | THIS_MODULE); | ||
696 | if (ipqnl == NULL) { | 697 | if (ipqnl == NULL) { |
697 | printk(KERN_ERR "ip_queue: failed to create netlink socket\n"); | 698 | printk(KERN_ERR "ip_queue: failed to create netlink socket\n"); |
698 | goto cleanup_netlink_notifier; | 699 | goto cleanup_netlink_notifier; |
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 52a0076302a7..4ea8371ab270 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c | |||
@@ -62,6 +62,7 @@ | |||
62 | MODULE_LICENSE("GPL"); | 62 | MODULE_LICENSE("GPL"); |
63 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | 63 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); |
64 | MODULE_DESCRIPTION("iptables userspace logging module"); | 64 | MODULE_DESCRIPTION("iptables userspace logging module"); |
65 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG); | ||
65 | 66 | ||
66 | #define ULOG_NL_EVENT 111 /* Harald's favorite number */ | 67 | #define ULOG_NL_EVENT 111 /* Harald's favorite number */ |
67 | #define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */ | 68 | #define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */ |
@@ -372,7 +373,7 @@ static int __init init(void) | |||
372 | ulog_buffers[i].timer.data = i; | 373 | ulog_buffers[i].timer.data = i; |
373 | } | 374 | } |
374 | 375 | ||
375 | nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL); | 376 | nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL, THIS_MODULE); |
376 | if (!nflognl) | 377 | if (!nflognl) |
377 | return -ENOMEM; | 378 | return -ENOMEM; |
378 | 379 | ||
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index f66945cb158f..f79bd11a4701 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c | |||
@@ -774,7 +774,8 @@ static void tcpdiag_rcv(struct sock *sk, int len) | |||
774 | 774 | ||
775 | static int __init tcpdiag_init(void) | 775 | static int __init tcpdiag_init(void) |
776 | { | 776 | { |
777 | tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv); | 777 | tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv, |
778 | THIS_MODULE); | ||
778 | if (tcpnl == NULL) | 779 | if (tcpnl == NULL) |
779 | return -ENOMEM; | 780 | return -ENOMEM; |
780 | return 0; | 781 | return 0; |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 7130603a32c5..1c3d247a22cc 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -685,7 +685,7 @@ init_or_cleanup(int init) | |||
685 | goto cleanup; | 685 | goto cleanup; |
686 | 686 | ||
687 | netlink_register_notifier(&ipq_nl_notifier); | 687 | netlink_register_notifier(&ipq_nl_notifier); |
688 | ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk); | 688 | ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk, THIS_MODULE); |
689 | if (ipqnl == NULL) { | 689 | if (ipqnl == NULL) { |
690 | printk(KERN_ERR "ip6_queue: failed to create netlink socket\n"); | 690 | printk(KERN_ERR "ip6_queue: failed to create netlink socket\n"); |
691 | goto cleanup_netlink_notifier; | 691 | goto cleanup_netlink_notifier; |
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index b0ed57981847..6210ca42166c 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <linux/netfilter/nfnetlink.h> | 38 | #include <linux/netfilter/nfnetlink.h> |
39 | 39 | ||
40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
41 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
42 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); | ||
41 | 43 | ||
42 | static char __initdata nfversion[] = "0.30"; | 44 | static char __initdata nfversion[] = "0.30"; |
43 | 45 | ||
@@ -324,7 +326,8 @@ int __init nfnetlink_init(void) | |||
324 | { | 326 | { |
325 | printk("Netfilter messages via NETLINK v%s.\n", nfversion); | 327 | printk("Netfilter messages via NETLINK v%s.\n", nfversion); |
326 | 328 | ||
327 | nfnl = netlink_kernel_create(NETLINK_NETFILTER, nfnetlink_rcv); | 329 | nfnl = netlink_kernel_create(NETLINK_NETFILTER, nfnetlink_rcv, |
330 | THIS_MODULE); | ||
328 | if (!nfnl) { | 331 | if (!nfnl) { |
329 | printk(KERN_ERR "cannot initialize nfnetlink!\n"); | 332 | printk(KERN_ERR "cannot initialize nfnetlink!\n"); |
330 | return -1; | 333 | return -1; |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index ff774a06c89d..5d487cd69c8c 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -13,7 +13,12 @@ | |||
13 | * added netlink_proto_exit | 13 | * added netlink_proto_exit |
14 | * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br> | 14 | * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br> |
15 | * use nlk_sk, as sk->protinfo is on a diet 8) | 15 | * use nlk_sk, as sk->protinfo is on a diet 8) |
16 | * | 16 | * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org> |
17 | * - inc module use count of module that owns | ||
18 | * the kernel socket in case userspace opens | ||
19 | * socket of same protocol | ||
20 | * - remove all module support, since netlink is | ||
21 | * mandatory if CONFIG_NET=y these days | ||
17 | */ | 22 | */ |
18 | 23 | ||
19 | #include <linux/config.h> | 24 | #include <linux/config.h> |
@@ -92,6 +97,7 @@ struct netlink_table { | |||
92 | struct nl_pid_hash hash; | 97 | struct nl_pid_hash hash; |
93 | struct hlist_head mc_list; | 98 | struct hlist_head mc_list; |
94 | unsigned int nl_nonroot; | 99 | unsigned int nl_nonroot; |
100 | struct proto_ops *p_ops; | ||
95 | }; | 101 | }; |
96 | 102 | ||
97 | static struct netlink_table *nl_table; | 103 | static struct netlink_table *nl_table; |
@@ -341,7 +347,21 @@ static int netlink_create(struct socket *sock, int protocol) | |||
341 | if (protocol<0 || protocol >= MAX_LINKS) | 347 | if (protocol<0 || protocol >= MAX_LINKS) |
342 | return -EPROTONOSUPPORT; | 348 | return -EPROTONOSUPPORT; |
343 | 349 | ||
344 | sock->ops = &netlink_ops; | 350 | netlink_table_grab(); |
351 | if (!nl_table[protocol].hash.entries) { | ||
352 | #ifdef CONFIG_KMOD | ||
353 | /* We do 'best effort'. If we find a matching module, | ||
354 | * it is loaded. If not, we don't return an error to | ||
355 | * allow pure userspace<->userspace communication. -HW | ||
356 | */ | ||
357 | netlink_table_ungrab(); | ||
358 | request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); | ||
359 | netlink_table_grab(); | ||
360 | #endif | ||
361 | } | ||
362 | netlink_table_ungrab(); | ||
363 | |||
364 | sock->ops = nl_table[protocol].p_ops; | ||
345 | 365 | ||
346 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); | 366 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); |
347 | if (!sk) | 367 | if (!sk) |
@@ -394,6 +414,22 @@ static int netlink_release(struct socket *sock) | |||
394 | }; | 414 | }; |
395 | notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); | 415 | notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); |
396 | } | 416 | } |
417 | |||
418 | /* When this is a kernel socket, we need to remove the owner pointer, | ||
419 | * since we don't know whether the module will be dying at any given | ||
420 | * point - HW | ||
421 | */ | ||
422 | if (!nlk->pid) { | ||
423 | struct proto_ops *p_tmp; | ||
424 | |||
425 | netlink_table_grab(); | ||
426 | p_tmp = nl_table[sk->sk_protocol].p_ops; | ||
427 | if (p_tmp != &netlink_ops) { | ||
428 | nl_table[sk->sk_protocol].p_ops = &netlink_ops; | ||
429 | kfree(p_tmp); | ||
430 | } | ||
431 | netlink_table_ungrab(); | ||
432 | } | ||
397 | 433 | ||
398 | sock_put(sk); | 434 | sock_put(sk); |
399 | return 0; | 435 | return 0; |
@@ -1023,8 +1059,9 @@ static void netlink_data_ready(struct sock *sk, int len) | |||
1023 | */ | 1059 | */ |
1024 | 1060 | ||
1025 | struct sock * | 1061 | struct sock * |
1026 | netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)) | 1062 | netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct module *module) |
1027 | { | 1063 | { |
1064 | struct proto_ops *p_ops; | ||
1028 | struct socket *sock; | 1065 | struct socket *sock; |
1029 | struct sock *sk; | 1066 | struct sock *sk; |
1030 | 1067 | ||
@@ -1034,22 +1071,63 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)) | |||
1034 | if (unit<0 || unit>=MAX_LINKS) | 1071 | if (unit<0 || unit>=MAX_LINKS) |
1035 | return NULL; | 1072 | return NULL; |
1036 | 1073 | ||
1074 | /* Do a quick check, to make us not go down to netlink_insert() | ||
1075 | * if protocol already has kernel socket. | ||
1076 | */ | ||
1077 | sk = netlink_lookup(unit, 0); | ||
1078 | if (unlikely(sk)) { | ||
1079 | sock_put(sk); | ||
1080 | return NULL; | ||
1081 | } | ||
1082 | |||
1037 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) | 1083 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) |
1038 | return NULL; | 1084 | return NULL; |
1039 | 1085 | ||
1086 | sk = NULL; | ||
1087 | if (module) { | ||
1088 | /* Every registering protocol implemented in a module needs | ||
1089 | * it's own p_ops, since the socket code cannot deal with | ||
1090 | * module refcounting otherwise. -HW | ||
1091 | */ | ||
1092 | p_ops = kmalloc(sizeof(*p_ops), GFP_KERNEL); | ||
1093 | if (!p_ops) | ||
1094 | goto out_sock_release; | ||
1095 | |||
1096 | memcpy(p_ops, &netlink_ops, sizeof(*p_ops)); | ||
1097 | p_ops->owner = module; | ||
1098 | } else | ||
1099 | p_ops = &netlink_ops; | ||
1100 | |||
1101 | netlink_table_grab(); | ||
1102 | nl_table[unit].p_ops = p_ops; | ||
1103 | netlink_table_ungrab(); | ||
1104 | |||
1040 | if (netlink_create(sock, unit) < 0) { | 1105 | if (netlink_create(sock, unit) < 0) { |
1041 | sock_release(sock); | 1106 | sk = NULL; |
1042 | return NULL; | 1107 | goto out_kfree_p_ops; |
1043 | } | 1108 | } |
1109 | |||
1044 | sk = sock->sk; | 1110 | sk = sock->sk; |
1045 | sk->sk_data_ready = netlink_data_ready; | 1111 | sk->sk_data_ready = netlink_data_ready; |
1046 | if (input) | 1112 | if (input) |
1047 | nlk_sk(sk)->data_ready = input; | 1113 | nlk_sk(sk)->data_ready = input; |
1048 | 1114 | ||
1049 | if (netlink_insert(sk, 0)) { | 1115 | if (netlink_insert(sk, 0)) { |
1050 | sock_release(sock); | 1116 | sk = NULL; |
1051 | return NULL; | 1117 | goto out_kfree_p_ops; |
1118 | } | ||
1119 | |||
1120 | return sk; | ||
1121 | |||
1122 | out_kfree_p_ops: | ||
1123 | netlink_table_grab(); | ||
1124 | if (nl_table[unit].p_ops != &netlink_ops) { | ||
1125 | kfree(nl_table[unit].p_ops); | ||
1126 | nl_table[unit].p_ops = &netlink_ops; | ||
1052 | } | 1127 | } |
1128 | netlink_table_ungrab(); | ||
1129 | out_sock_release: | ||
1130 | sock_release(sock); | ||
1053 | return sk; | 1131 | return sk; |
1054 | } | 1132 | } |
1055 | 1133 | ||
@@ -1413,6 +1491,8 @@ enomem: | |||
1413 | for (i = 0; i < MAX_LINKS; i++) { | 1491 | for (i = 0; i < MAX_LINKS; i++) { |
1414 | struct nl_pid_hash *hash = &nl_table[i].hash; | 1492 | struct nl_pid_hash *hash = &nl_table[i].hash; |
1415 | 1493 | ||
1494 | nl_table[i].p_ops = &netlink_ops; | ||
1495 | |||
1416 | hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table)); | 1496 | hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table)); |
1417 | if (!hash->table) { | 1497 | if (!hash->table) { |
1418 | while (i-- > 0) | 1498 | while (i-- > 0) |
@@ -1438,21 +1518,7 @@ out: | |||
1438 | return err; | 1518 | return err; |
1439 | } | 1519 | } |
1440 | 1520 | ||
1441 | static void __exit netlink_proto_exit(void) | ||
1442 | { | ||
1443 | sock_unregister(PF_NETLINK); | ||
1444 | proc_net_remove("netlink"); | ||
1445 | kfree(nl_table); | ||
1446 | nl_table = NULL; | ||
1447 | proto_unregister(&netlink_proto); | ||
1448 | } | ||
1449 | |||
1450 | core_initcall(netlink_proto_init); | 1521 | core_initcall(netlink_proto_init); |
1451 | module_exit(netlink_proto_exit); | ||
1452 | |||
1453 | MODULE_LICENSE("GPL"); | ||
1454 | |||
1455 | MODULE_ALIAS_NETPROTO(PF_NETLINK); | ||
1456 | 1522 | ||
1457 | EXPORT_SYMBOL(netlink_ack); | 1523 | EXPORT_SYMBOL(netlink_ack); |
1458 | EXPORT_SYMBOL(netlink_broadcast); | 1524 | EXPORT_SYMBOL(netlink_broadcast); |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 8da3e25b2c4c..33ceeea783b1 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1519,7 +1519,8 @@ static int __init xfrm_user_init(void) | |||
1519 | { | 1519 | { |
1520 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); | 1520 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); |
1521 | 1521 | ||
1522 | xfrm_nl = netlink_kernel_create(NETLINK_XFRM, xfrm_netlink_rcv); | 1522 | xfrm_nl = netlink_kernel_create(NETLINK_XFRM, xfrm_netlink_rcv, |
1523 | THIS_MODULE); | ||
1523 | if (xfrm_nl == NULL) | 1524 | if (xfrm_nl == NULL) |
1524 | return -ENOMEM; | 1525 | return -ENOMEM; |
1525 | 1526 | ||
@@ -1537,3 +1538,4 @@ static void __exit xfrm_user_exit(void) | |||
1537 | module_init(xfrm_user_init); | 1538 | module_init(xfrm_user_init); |
1538 | module_exit(xfrm_user_exit); | 1539 | module_exit(xfrm_user_exit); |
1539 | MODULE_LICENSE("GPL"); | 1540 | MODULE_LICENSE("GPL"); |
1541 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); | ||
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index 18d08acafa78..341dbe2579be 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c | |||
@@ -103,7 +103,7 @@ void selnl_notify_policyload(u32 seqno) | |||
103 | 103 | ||
104 | static int __init selnl_init(void) | 104 | static int __init selnl_init(void) |
105 | { | 105 | { |
106 | selnl = netlink_kernel_create(NETLINK_SELINUX, NULL); | 106 | selnl = netlink_kernel_create(NETLINK_SELINUX, NULL, THIS_MODULE); |
107 | if (selnl == NULL) | 107 | if (selnl == NULL) |
108 | panic("SELinux: Cannot create netlink socket."); | 108 | panic("SELinux: Cannot create netlink socket."); |
109 | netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV); | 109 | netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV); |