diff options
Diffstat (limited to 'net/packet/af_packet.c')
| -rw-r--r-- | net/packet/af_packet.c | 50 |
1 files changed, 20 insertions, 30 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9db7dbdb16e6..f4ccb90e6739 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
| @@ -49,7 +49,6 @@ | |||
| 49 | * | 49 | * |
| 50 | */ | 50 | */ |
| 51 | 51 | ||
| 52 | #include <linux/config.h> | ||
| 53 | #include <linux/types.h> | 52 | #include <linux/types.h> |
| 54 | #include <linux/sched.h> | 53 | #include <linux/sched.h> |
| 55 | #include <linux/mm.h> | 54 | #include <linux/mm.h> |
| @@ -428,21 +427,24 @@ out_unlock: | |||
| 428 | } | 427 | } |
| 429 | #endif | 428 | #endif |
| 430 | 429 | ||
| 431 | static inline unsigned run_filter(struct sk_buff *skb, struct sock *sk, unsigned res) | 430 | static inline int run_filter(struct sk_buff *skb, struct sock *sk, |
| 431 | unsigned *snaplen) | ||
| 432 | { | 432 | { |
| 433 | struct sk_filter *filter; | 433 | struct sk_filter *filter; |
| 434 | int err = 0; | ||
| 434 | 435 | ||
| 435 | bh_lock_sock(sk); | 436 | rcu_read_lock_bh(); |
| 436 | filter = sk->sk_filter; | 437 | filter = rcu_dereference(sk->sk_filter); |
| 437 | /* | 438 | if (filter != NULL) { |
| 438 | * Our caller already checked that filter != NULL but we need to | 439 | err = sk_run_filter(skb, filter->insns, filter->len); |
| 439 | * verify that under bh_lock_sock() to be safe | 440 | if (!err) |
| 440 | */ | 441 | err = -EPERM; |
| 441 | if (likely(filter != NULL)) | 442 | else if (*snaplen > err) |
| 442 | res = sk_run_filter(skb, filter->insns, filter->len); | 443 | *snaplen = err; |
| 443 | bh_unlock_sock(sk); | 444 | } |
| 445 | rcu_read_unlock_bh(); | ||
| 444 | 446 | ||
| 445 | return res; | 447 | return err; |
| 446 | } | 448 | } |
| 447 | 449 | ||
| 448 | /* | 450 | /* |
| @@ -492,13 +494,8 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
| 492 | 494 | ||
| 493 | snaplen = skb->len; | 495 | snaplen = skb->len; |
| 494 | 496 | ||
| 495 | if (sk->sk_filter) { | 497 | if (run_filter(skb, sk, &snaplen) < 0) |
| 496 | unsigned res = run_filter(skb, sk, snaplen); | 498 | goto drop_n_restore; |
| 497 | if (res == 0) | ||
| 498 | goto drop_n_restore; | ||
| 499 | if (snaplen > res) | ||
| 500 | snaplen = res; | ||
| 501 | } | ||
| 502 | 499 | ||
| 503 | if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= | 500 | if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= |
| 504 | (unsigned)sk->sk_rcvbuf) | 501 | (unsigned)sk->sk_rcvbuf) |
| @@ -587,20 +584,15 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
| 587 | else if (skb->pkt_type == PACKET_OUTGOING) { | 584 | else if (skb->pkt_type == PACKET_OUTGOING) { |
| 588 | /* Special case: outgoing packets have ll header at head */ | 585 | /* Special case: outgoing packets have ll header at head */ |
| 589 | skb_pull(skb, skb->nh.raw - skb->data); | 586 | skb_pull(skb, skb->nh.raw - skb->data); |
| 590 | if (skb->ip_summed == CHECKSUM_HW) | 587 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
| 591 | status |= TP_STATUS_CSUMNOTREADY; | 588 | status |= TP_STATUS_CSUMNOTREADY; |
| 592 | } | 589 | } |
| 593 | } | 590 | } |
| 594 | 591 | ||
| 595 | snaplen = skb->len; | 592 | snaplen = skb->len; |
| 596 | 593 | ||
| 597 | if (sk->sk_filter) { | 594 | if (run_filter(skb, sk, &snaplen) < 0) |
| 598 | unsigned res = run_filter(skb, sk, snaplen); | 595 | goto drop_n_restore; |
| 599 | if (res == 0) | ||
| 600 | goto drop_n_restore; | ||
| 601 | if (snaplen > res) | ||
| 602 | snaplen = res; | ||
| 603 | } | ||
| 604 | 596 | ||
| 605 | if (sk->sk_type == SOCK_DGRAM) { | 597 | if (sk->sk_type == SOCK_DGRAM) { |
| 606 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; | 598 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; |
| @@ -627,8 +619,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
| 627 | if ((int)snaplen < 0) | 619 | if ((int)snaplen < 0) |
| 628 | snaplen = 0; | 620 | snaplen = 0; |
| 629 | } | 621 | } |
| 630 | if (snaplen > skb->len-skb->data_len) | ||
| 631 | snaplen = skb->len-skb->data_len; | ||
| 632 | 622 | ||
| 633 | spin_lock(&sk->sk_receive_queue.lock); | 623 | spin_lock(&sk->sk_receive_queue.lock); |
| 634 | h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head); | 624 | h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head); |
| @@ -645,7 +635,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
| 645 | status &= ~TP_STATUS_LOSING; | 635 | status &= ~TP_STATUS_LOSING; |
| 646 | spin_unlock(&sk->sk_receive_queue.lock); | 636 | spin_unlock(&sk->sk_receive_queue.lock); |
| 647 | 637 | ||
| 648 | memcpy((u8*)h + macoff, skb->data, snaplen); | 638 | skb_copy_bits(skb, 0, (u8*)h + macoff, snaplen); |
| 649 | 639 | ||
| 650 | h->tp_len = skb->len; | 640 | h->tp_len = skb->len; |
| 651 | h->tp_snaplen = snaplen; | 641 | h->tp_snaplen = snaplen; |
