aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Kuznetsov <kuznet@ms2.inr.ac.ru>2006-02-09 19:40:11 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-02-09 19:43:38 -0500
commita70ea994a0d83fd0151a070be72b87d014ef0a7e (patch)
tree40e3bf28a3fa36f20b4625c241ca14abb0c1a00d
parentad91e6fa0d331e419e4692d146cdc04e594a5bea (diff)
[NETLINK]: Fix a severe bug
netlink overrun was broken while improvement of netlink. Destination socket is used in the place where it was meant to be source socket, so that now overrun is never sent to user netlink sockets, when it should be, and it even can be set on kernel socket, which results in complete deadlock of rtnetlink. Suggested fix is to restore status quo passing source socket as additional argument to netlink_attachskb(). A little explanation: overrun is set on a socket, when it failed to receive some message and sender of this messages does not or even have no way to handle this error. This happens in two cases: 1. when kernel sends something. Kernel never retransmits and cannot wait for buffer space. 2. when user sends a broadcast and the message was not delivered to some recipients. Signed-off-by: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netlink.h3
-rw-r--r--ipc/mqueue.c3
-rw-r--r--net/netlink/af_netlink.c7
3 files changed, 8 insertions, 5 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 6a2ccf78a356..c256ebe2a7b4 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -160,7 +160,8 @@ extern int netlink_unregister_notifier(struct notifier_block *nb);
160 160
161/* finegrained unicast helpers: */ 161/* finegrained unicast helpers: */
162struct sock *netlink_getsockbyfilp(struct file *filp); 162struct sock *netlink_getsockbyfilp(struct file *filp);
163int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long timeo); 163int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
164 long timeo, struct sock *ssk);
164void netlink_detachskb(struct sock *sk, struct sk_buff *skb); 165void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
165int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); 166int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
166 167
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 59302fc3643b..fd2e26b6f966 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1018,7 +1018,8 @@ retry:
1018 goto out; 1018 goto out;
1019 } 1019 }
1020 1020
1021 ret = netlink_attachskb(sock, nc, 0, MAX_SCHEDULE_TIMEOUT); 1021 ret = netlink_attachskb(sock, nc, 0,
1022 MAX_SCHEDULE_TIMEOUT, NULL);
1022 if (ret == 1) 1023 if (ret == 1)
1023 goto retry; 1024 goto retry;
1024 if (ret) { 1025 if (ret) {
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 2101b45d2ec6..6b9772d95872 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -702,7 +702,8 @@ struct sock *netlink_getsockbyfilp(struct file *filp)
702 * 0: continue 702 * 0: continue
703 * 1: repeat lookup - reference dropped while waiting for socket memory. 703 * 1: repeat lookup - reference dropped while waiting for socket memory.
704 */ 704 */
705int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long timeo) 705int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
706 long timeo, struct sock *ssk)
706{ 707{
707 struct netlink_sock *nlk; 708 struct netlink_sock *nlk;
708 709
@@ -712,7 +713,7 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t
712 test_bit(0, &nlk->state)) { 713 test_bit(0, &nlk->state)) {
713 DECLARE_WAITQUEUE(wait, current); 714 DECLARE_WAITQUEUE(wait, current);
714 if (!timeo) { 715 if (!timeo) {
715 if (!nlk->pid) 716 if (!ssk || nlk_sk(ssk)->pid == 0)
716 netlink_overrun(sk); 717 netlink_overrun(sk);
717 sock_put(sk); 718 sock_put(sk);
718 kfree_skb(skb); 719 kfree_skb(skb);
@@ -797,7 +798,7 @@ retry:
797 kfree_skb(skb); 798 kfree_skb(skb);
798 return PTR_ERR(sk); 799 return PTR_ERR(sk);
799 } 800 }
800 err = netlink_attachskb(sk, skb, nonblock, timeo); 801 err = netlink_attachskb(sk, skb, nonblock, timeo, ssk);
801 if (err == 1) 802 if (err == 1)
802 goto retry; 803 goto retry;
803 if (err) 804 if (err)