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) |
