aboutsummaryrefslogtreecommitdiffstats
path: root/net/packet/af_packet.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-01-24 18:21:02 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-01-24 18:21:02 -0500
commitdbcb5855d108b7fa20ab42567a5412ce9dcd776a (patch)
treeb1c165e43ef28d9e22c118e8cbb983431ace3c7a /net/packet/af_packet.c
parent6640e69731b42fd5e3d2b26201c8b34fc897a0ee (diff)
[AF_PACKET]: Fix BPF handling.
This fixes a bug introduced by: commit fda9ef5d679b07c9d9097aaf6ef7f069d794a8f9 Author: Dmitry Mishin <dim@openvz.org> Date: Thu Aug 31 15:28:39 2006 -0700 [NET]: Fix sk->sk_filter field access sk_run_filter() returns either 0 or an unsigned 32-bit length which says how much of the packet to retain. If that 32-bit unsigned integer is larger than the packet, this is fine we just leave the packet unchanged. The above commit caused all filter return values which were negative when interpreted as a signed integer to indicate a packet drop, which is wrong. Based upon a report and initial patch by Raivis Bucis. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r--net/packet/af_packet.c30
1 files changed, 15 insertions, 15 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index da73e8a8c18d..594c078c5ebc 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -428,24 +428,18 @@ out_unlock:
428} 428}
429#endif 429#endif
430 430
431static inline int run_filter(struct sk_buff *skb, struct sock *sk, 431static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk,
432 unsigned *snaplen) 432 unsigned int res)
433{ 433{
434 struct sk_filter *filter; 434 struct sk_filter *filter;
435 int err = 0;
436 435
437 rcu_read_lock_bh(); 436 rcu_read_lock_bh();
438 filter = rcu_dereference(sk->sk_filter); 437 filter = rcu_dereference(sk->sk_filter);
439 if (filter != NULL) { 438 if (filter != NULL)
440 err = sk_run_filter(skb, filter->insns, filter->len); 439 res = sk_run_filter(skb, filter->insns, filter->len);
441 if (!err)
442 err = -EPERM;
443 else if (*snaplen > err)
444 *snaplen = err;
445 }
446 rcu_read_unlock_bh(); 440 rcu_read_unlock_bh();
447 441
448 return err; 442 return res;
449} 443}
450 444
451/* 445/*
@@ -467,7 +461,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
467 struct packet_sock *po; 461 struct packet_sock *po;
468 u8 * skb_head = skb->data; 462 u8 * skb_head = skb->data;
469 int skb_len = skb->len; 463 int skb_len = skb->len;
470 unsigned snaplen; 464 unsigned int snaplen, res;
471 465
472 if (skb->pkt_type == PACKET_LOOPBACK) 466 if (skb->pkt_type == PACKET_LOOPBACK)
473 goto drop; 467 goto drop;
@@ -495,8 +489,11 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
495 489
496 snaplen = skb->len; 490 snaplen = skb->len;
497 491
498 if (run_filter(skb, sk, &snaplen) < 0) 492 res = run_filter(skb, sk, snaplen);
493 if (!res)
499 goto drop_n_restore; 494 goto drop_n_restore;
495 if (snaplen > res)
496 snaplen = res;
500 497
501 if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= 498 if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
502 (unsigned)sk->sk_rcvbuf) 499 (unsigned)sk->sk_rcvbuf)
@@ -568,7 +565,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
568 struct tpacket_hdr *h; 565 struct tpacket_hdr *h;
569 u8 * skb_head = skb->data; 566 u8 * skb_head = skb->data;
570 int skb_len = skb->len; 567 int skb_len = skb->len;
571 unsigned snaplen; 568 unsigned int snaplen, res;
572 unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; 569 unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
573 unsigned short macoff, netoff; 570 unsigned short macoff, netoff;
574 struct sk_buff *copy_skb = NULL; 571 struct sk_buff *copy_skb = NULL;
@@ -592,8 +589,11 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
592 589
593 snaplen = skb->len; 590 snaplen = skb->len;
594 591
595 if (run_filter(skb, sk, &snaplen) < 0) 592 res = run_filter(skb, sk, snaplen);
593 if (!res)
596 goto drop_n_restore; 594 goto drop_n_restore;
595 if (snaplen > res)
596 snaplen = res;
597 597
598 if (sk->sk_type == SOCK_DGRAM) { 598 if (sk->sk_type == SOCK_DGRAM) {
599 macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; 599 macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16;