diff options
-rw-r--r-- | kernel/audit.c | 19 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 23 | ||||
-rw-r--r-- | net/decnet/netfilter/dn_rtmsg.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 20 | ||||
-rw-r--r-- | net/ipv4/tcp_diag.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 20 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 15 |
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. */ |
430 | static int audit_receive_skb(struct sk_buff *skb) | 430 | static 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. */ |
453 | static void audit_receive(struct sock *sk, int length) | 452 | static 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 | ||
618 | static void rtnetlink_rcv(struct sock *sk, int len) | 617 | static 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 | ||
644 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = | 649 | static 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) | |||
119 | static void dnrmg_receive_user_sk(struct sock *sk, int len) | 119 | static 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) | |||
546 | static void | 546 | static void |
547 | ipq_rcv_sk(struct sock *sk, int len) | 547 | ipq_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 | ||
565 | static int | 563 | static 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) | |||
777 | static void tcpdiag_rcv(struct sock *sk, int len) | 777 | static 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) | |||
549 | static void | 549 | static void |
550 | ipq_rcv_sk(struct sock *sk, int len) | 550 | ipq_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 | ||
568 | static int | 566 | static 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 | ||
1009 | static void xfrm_netlink_rcv(struct sock *sk, int len) | 1009 | static 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 | ||
1033 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) | 1040 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) |