diff options
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 45 |
1 files changed, 19 insertions, 26 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 4172a5235916..f4ccb90e6739 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -427,21 +427,24 @@ out_unlock: | |||
427 | } | 427 | } |
428 | #endif | 428 | #endif |
429 | 429 | ||
430 | 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) | ||
431 | { | 432 | { |
432 | struct sk_filter *filter; | 433 | struct sk_filter *filter; |
434 | int err = 0; | ||
433 | 435 | ||
434 | bh_lock_sock(sk); | 436 | rcu_read_lock_bh(); |
435 | filter = sk->sk_filter; | 437 | filter = rcu_dereference(sk->sk_filter); |
436 | /* | 438 | if (filter != NULL) { |
437 | * Our caller already checked that filter != NULL but we need to | 439 | err = sk_run_filter(skb, filter->insns, filter->len); |
438 | * verify that under bh_lock_sock() to be safe | 440 | if (!err) |
439 | */ | 441 | err = -EPERM; |
440 | if (likely(filter != NULL)) | 442 | else if (*snaplen > err) |
441 | res = sk_run_filter(skb, filter->insns, filter->len); | 443 | *snaplen = err; |
442 | bh_unlock_sock(sk); | 444 | } |
445 | rcu_read_unlock_bh(); | ||
443 | 446 | ||
444 | return res; | 447 | return err; |
445 | } | 448 | } |
446 | 449 | ||
447 | /* | 450 | /* |
@@ -491,13 +494,8 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
491 | 494 | ||
492 | snaplen = skb->len; | 495 | snaplen = skb->len; |
493 | 496 | ||
494 | if (sk->sk_filter) { | 497 | if (run_filter(skb, sk, &snaplen) < 0) |
495 | unsigned res = run_filter(skb, sk, snaplen); | 498 | goto drop_n_restore; |
496 | if (res == 0) | ||
497 | goto drop_n_restore; | ||
498 | if (snaplen > res) | ||
499 | snaplen = res; | ||
500 | } | ||
501 | 499 | ||
502 | if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= | 500 | if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= |
503 | (unsigned)sk->sk_rcvbuf) | 501 | (unsigned)sk->sk_rcvbuf) |
@@ -586,20 +584,15 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
586 | else if (skb->pkt_type == PACKET_OUTGOING) { | 584 | else if (skb->pkt_type == PACKET_OUTGOING) { |
587 | /* Special case: outgoing packets have ll header at head */ | 585 | /* Special case: outgoing packets have ll header at head */ |
588 | skb_pull(skb, skb->nh.raw - skb->data); | 586 | skb_pull(skb, skb->nh.raw - skb->data); |
589 | if (skb->ip_summed == CHECKSUM_HW) | 587 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
590 | status |= TP_STATUS_CSUMNOTREADY; | 588 | status |= TP_STATUS_CSUMNOTREADY; |
591 | } | 589 | } |
592 | } | 590 | } |
593 | 591 | ||
594 | snaplen = skb->len; | 592 | snaplen = skb->len; |
595 | 593 | ||
596 | if (sk->sk_filter) { | 594 | if (run_filter(skb, sk, &snaplen) < 0) |
597 | unsigned res = run_filter(skb, sk, snaplen); | 595 | goto drop_n_restore; |
598 | if (res == 0) | ||
599 | goto drop_n_restore; | ||
600 | if (snaplen > res) | ||
601 | snaplen = res; | ||
602 | } | ||
603 | 596 | ||
604 | if (sk->sk_type == SOCK_DGRAM) { | 597 | if (sk->sk_type == SOCK_DGRAM) { |
605 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; | 598 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; |