aboutsummaryrefslogtreecommitdiffstats
path: root/net/packet/af_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r--net/packet/af_packet.c50
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
431static inline unsigned run_filter(struct sk_buff *skb, struct sock *sk, unsigned res) 430static 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;