aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/audit.c19
-rw-r--r--net/core/rtnetlink.c23
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c3
-rw-r--r--net/ipv4/netfilter/ip_queue.c20
-rw-r--r--net/ipv4/tcp_diag.c3
-rw-r--r--net/ipv6/netfilter/ip6_queue.c20
-rw-r--r--net/xfrm/xfrm_user.c15
7 files changed, 55 insertions, 48 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index 0f84dd7af2c8..ac26d4d960d3 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -427,7 +427,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
427/* Get message from skb (based on rtnetlink_rcv_skb). Each message is 427/* Get message from skb (based on rtnetlink_rcv_skb). Each message is
428 * processed by audit_receive_msg. Malformed skbs with wrong length are 428 * processed by audit_receive_msg. Malformed skbs with wrong length are
429 * discarded silently. */ 429 * discarded silently. */
430static int audit_receive_skb(struct sk_buff *skb) 430static void audit_receive_skb(struct sk_buff *skb)
431{ 431{
432 int err; 432 int err;
433 struct nlmsghdr *nlh; 433 struct nlmsghdr *nlh;
@@ -436,7 +436,7 @@ static int audit_receive_skb(struct sk_buff *skb)
436 while (skb->len >= NLMSG_SPACE(0)) { 436 while (skb->len >= NLMSG_SPACE(0)) {
437 nlh = (struct nlmsghdr *)skb->data; 437 nlh = (struct nlmsghdr *)skb->data;
438 if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) 438 if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
439 return 0; 439 return;
440 rlen = NLMSG_ALIGN(nlh->nlmsg_len); 440 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
441 if (rlen > skb->len) 441 if (rlen > skb->len)
442 rlen = skb->len; 442 rlen = skb->len;
@@ -446,23 +446,20 @@ static int audit_receive_skb(struct sk_buff *skb)
446 netlink_ack(skb, nlh, 0); 446 netlink_ack(skb, nlh, 0);
447 skb_pull(skb, rlen); 447 skb_pull(skb, rlen);
448 } 448 }
449 return 0;
450} 449}
451 450
452/* Receive messages from netlink socket. */ 451/* Receive messages from netlink socket. */
453static void audit_receive(struct sock *sk, int length) 452static void audit_receive(struct sock *sk, int length)
454{ 453{
455 struct sk_buff *skb; 454 struct sk_buff *skb;
455 unsigned int qlen;
456 456
457 if (down_trylock(&audit_netlink_sem)) 457 down(&audit_netlink_sem);
458 return;
459 458
460 /* FIXME: this must not cause starvation */ 459 for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
461 while ((skb = skb_dequeue(&sk->sk_receive_queue))) { 460 skb = skb_dequeue(&sk->sk_receive_queue);
462 if (audit_receive_skb(skb) && skb->len) 461 audit_receive_skb(skb);
463 skb_queue_head(&sk->sk_receive_queue, skb); 462 kfree_skb(skb);
464 else
465 kfree_skb(skb);
466 } 463 }
467 up(&audit_netlink_sem); 464 up(&audit_netlink_sem);
468} 465}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 5fb70cfa1085..6e1ab1e34b2e 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -609,26 +609,31 @@ static inline int rtnetlink_rcv_skb(struct sk_buff *skb)
609 609
610/* 610/*
611 * rtnetlink input queue processing routine: 611 * rtnetlink input queue processing routine:
612 * - try to acquire shared lock. If it is failed, defer processing. 612 * - process as much as there was in the queue upon entry.
613 * - feed skbs to rtnetlink_rcv_skb, until it refuse a message, 613 * - feed skbs to rtnetlink_rcv_skb, until it refuse a message,
614 * that will occur, when a dump started and/or acquisition of 614 * that will occur, when a dump started.
615 * exclusive lock failed.
616 */ 615 */
617 616
618static void rtnetlink_rcv(struct sock *sk, int len) 617static void rtnetlink_rcv(struct sock *sk, int len)
619{ 618{
619 unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
620
620 do { 621 do {
621 struct sk_buff *skb; 622 struct sk_buff *skb;
622 623
623 if (rtnl_shlock_nowait()) 624 rtnl_lock();
624 return; 625
626 if (qlen > skb_queue_len(&sk->sk_receive_queue))
627 qlen = skb_queue_len(&sk->sk_receive_queue);
625 628
626 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 629 while (qlen--) {
630 skb = skb_dequeue(&sk->sk_receive_queue);
627 if (rtnetlink_rcv_skb(skb)) { 631 if (rtnetlink_rcv_skb(skb)) {
628 if (skb->len) 632 if (skb->len) {
629 skb_queue_head(&sk->sk_receive_queue, 633 skb_queue_head(&sk->sk_receive_queue,
630 skb); 634 skb);
631 else 635 qlen++;
636 } else
632 kfree_skb(skb); 637 kfree_skb(skb);
633 break; 638 break;
634 } 639 }
@@ -638,7 +643,7 @@ static void rtnetlink_rcv(struct sock *sk, int len)
638 up(&rtnl_sem); 643 up(&rtnl_sem);
639 644
640 netdev_run_todo(); 645 netdev_run_todo();
641 } while (rtnl && rtnl->sk_receive_queue.qlen); 646 } while (qlen);
642} 647}
643 648
644static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = 649static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index f86a6259fd12..101ddef9ba9a 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -119,8 +119,9 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
119static void dnrmg_receive_user_sk(struct sock *sk, int len) 119static void dnrmg_receive_user_sk(struct sock *sk, int len)
120{ 120{
121 struct sk_buff *skb; 121 struct sk_buff *skb;
122 unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
122 123
123 while((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 124 while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {
124 dnrmg_receive_user_skb(skb); 125 dnrmg_receive_user_skb(skb);
125 kfree_skb(skb); 126 kfree_skb(skb);
126 } 127 }
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 9e40dffc204f..e5746b674413 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -546,20 +546,18 @@ ipq_rcv_skb(struct sk_buff *skb)
546static void 546static void
547ipq_rcv_sk(struct sock *sk, int len) 547ipq_rcv_sk(struct sock *sk, int len)
548{ 548{
549 do { 549 struct sk_buff *skb;
550 struct sk_buff *skb; 550 unsigned int qlen;
551 551
552 if (down_trylock(&ipqnl_sem)) 552 down(&ipqnl_sem);
553 return;
554 553
555 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 554 for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
556 ipq_rcv_skb(skb); 555 skb = skb_dequeue(&sk->sk_receive_queue);
557 kfree_skb(skb); 556 ipq_rcv_skb(skb);
558 } 557 kfree_skb(skb);
558 }
559 559
560 up(&ipqnl_sem); 560 up(&ipqnl_sem);
561
562 } while (ipqnl && ipqnl->sk_receive_queue.qlen);
563} 561}
564 562
565static int 563static int
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 313c1408da33..8faa8948f75c 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -777,8 +777,9 @@ static inline void tcpdiag_rcv_skb(struct sk_buff *skb)
777static void tcpdiag_rcv(struct sock *sk, int len) 777static void tcpdiag_rcv(struct sock *sk, int len)
778{ 778{
779 struct sk_buff *skb; 779 struct sk_buff *skb;
780 unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
780 781
781 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 782 while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {
782 tcpdiag_rcv_skb(skb); 783 tcpdiag_rcv_skb(skb);
783 kfree_skb(skb); 784 kfree_skb(skb);
784 } 785 }
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index c54830b89593..750943e2d34e 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -549,20 +549,18 @@ ipq_rcv_skb(struct sk_buff *skb)
549static void 549static void
550ipq_rcv_sk(struct sock *sk, int len) 550ipq_rcv_sk(struct sock *sk, int len)
551{ 551{
552 do { 552 struct sk_buff *skb;
553 struct sk_buff *skb; 553 unsigned int qlen;
554 554
555 if (down_trylock(&ipqnl_sem)) 555 down(&ipqnl_sem);
556 return;
557 556
558 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 557 for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
559 ipq_rcv_skb(skb); 558 skb = skb_dequeue(&sk->sk_receive_queue);
560 kfree_skb(skb); 559 ipq_rcv_skb(skb);
561 } 560 kfree_skb(skb);
561 }
562 562
563 up(&ipqnl_sem); 563 up(&ipqnl_sem);
564
565 } while (ipqnl && ipqnl->sk_receive_queue.qlen);
566} 564}
567 565
568static int 566static int
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 52b5843937c5..dab112f1dd8a 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1008,17 +1008,24 @@ static int xfrm_user_rcv_skb(struct sk_buff *skb)
1008 1008
1009static void xfrm_netlink_rcv(struct sock *sk, int len) 1009static void xfrm_netlink_rcv(struct sock *sk, int len)
1010{ 1010{
1011 unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
1012
1011 do { 1013 do {
1012 struct sk_buff *skb; 1014 struct sk_buff *skb;
1013 1015
1014 down(&xfrm_cfg_sem); 1016 down(&xfrm_cfg_sem);
1015 1017
1016 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 1018 if (qlen > skb_queue_len(&sk->sk_receive_queue))
1019 qlen = skb_queue_len(&sk->sk_receive_queue);
1020
1021 while (qlen--) {
1022 skb = skb_dequeue(&sk->sk_receive_queue);
1017 if (xfrm_user_rcv_skb(skb)) { 1023 if (xfrm_user_rcv_skb(skb)) {
1018 if (skb->len) 1024 if (skb->len) {
1019 skb_queue_head(&sk->sk_receive_queue, 1025 skb_queue_head(&sk->sk_receive_queue,
1020 skb); 1026 skb);
1021 else 1027 qlen++;
1028 } else
1022 kfree_skb(skb); 1029 kfree_skb(skb);
1023 break; 1030 break;
1024 } 1031 }
@@ -1027,7 +1034,7 @@ static void xfrm_netlink_rcv(struct sock *sk, int len)
1027 1034
1028 up(&xfrm_cfg_sem); 1035 up(&xfrm_cfg_sem);
1029 1036
1030 } while (xfrm_nl && xfrm_nl->sk_receive_queue.qlen); 1037 } while (qlen);
1031} 1038}
1032 1039
1033static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) 1040static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard)