Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

af_packet: don't emit packet on orig fanout group

If a packet is emitted on one socket in one group of fanout sockets,
it is transmitted again. It is thus read again on one of the sockets
of the fanout group. This result in a loop for software which
generate packets when receiving one.
This retransmission is not the intended behavior: a fanout group
must behave like a single socket. The packet should not be
transmitted on a socket if it originates from a socket belonging
to the same fanout group.

This patch fixes the issue by changing the transmission check to
take fanout group info account.

Reported-by: Aleksandr Kotov <a1k@mail.ru>
Signed-off-by: Eric Leblond <eric@regit.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Leblond and committed by
David S. Miller
c0de08d0 9915e67e

+25 -2
+2
include/linux/netdevice.h
··· 1522 1522 struct sk_buff **(*gro_receive)(struct sk_buff **head, 1523 1523 struct sk_buff *skb); 1524 1524 int (*gro_complete)(struct sk_buff *skb); 1525 + bool (*id_match)(struct packet_type *ptype, 1526 + struct sock *sk); 1525 1527 void *af_packet_priv; 1526 1528 struct list_head list; 1527 1529 };
+14 -2
net/core/dev.c
··· 1642 1642 return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); 1643 1643 } 1644 1644 1645 + static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb) 1646 + { 1647 + if (ptype->af_packet_priv == NULL) 1648 + return false; 1649 + 1650 + if (ptype->id_match) 1651 + return ptype->id_match(ptype, skb->sk); 1652 + else if ((struct sock *)ptype->af_packet_priv == skb->sk) 1653 + return true; 1654 + 1655 + return false; 1656 + } 1657 + 1645 1658 /* 1646 1659 * Support routine. Sends outgoing frames to any network 1647 1660 * taps currently in use. ··· 1672 1659 * they originated from - MvS (miquels@drinkel.ow.org) 1673 1660 */ 1674 1661 if ((ptype->dev == dev || !ptype->dev) && 1675 - (ptype->af_packet_priv == NULL || 1676 - (struct sock *)ptype->af_packet_priv != skb->sk)) { 1662 + (!skb_loop_sk(ptype, skb))) { 1677 1663 if (pt_prev) { 1678 1664 deliver_skb(skb2, pt_prev, skb->dev); 1679 1665 pt_prev = ptype;
+9
net/packet/af_packet.c
··· 1273 1273 spin_unlock(&f->lock); 1274 1274 } 1275 1275 1276 + bool match_fanout_group(struct packet_type *ptype, struct sock * sk) 1277 + { 1278 + if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout) 1279 + return true; 1280 + 1281 + return false; 1282 + } 1283 + 1276 1284 static int fanout_add(struct sock *sk, u16 id, u16 type_flags) 1277 1285 { 1278 1286 struct packet_sock *po = pkt_sk(sk); ··· 1333 1325 match->prot_hook.dev = po->prot_hook.dev; 1334 1326 match->prot_hook.func = packet_rcv_fanout; 1335 1327 match->prot_hook.af_packet_priv = match; 1328 + match->prot_hook.id_match = match_fanout_group; 1336 1329 dev_add_pack(&match->prot_hook); 1337 1330 list_add(&match->list, &fanout_list); 1338 1331 }