summaryrefslogtreecommitdiffstats
path: root/net/packet
diff options
context:
space:
mode:
authorMike Maloney <maloney@google.com>2017-04-21 10:56:11 -0400
committerDavid S. Miller <davem@davemloft.net>2017-04-24 12:46:00 -0400
commit4a69a864209e9ab436d4a58e8028ac96cc873d15 (patch)
treebf8f3666194ccbfc21b3173db46a18e36b390b4e /net/packet
parent2e7a721714b9cdca539da78a0eb1f59dbe4020ac (diff)
packet: add PACKET_FANOUT_FLAG_UNIQUEID to assign new fanout group id.
Fanout uses a per net global namespace. A process that intends to create a new fanout group can accidentally join an existing group. It is not possible to detect this. Add socket option PACKET_FANOUT_FLAG_UNIQUEID. When specified the supplied fanout group id must be set to 0, and the kernel chooses an id that is not already in use. This is an ephemeral flag so that other sockets can be added to this group using setsockopt, but NOT specifying this flag. The current getsockopt(..., PACKET_FANOUT, ...) can be used to retrieve the new group id. We assume that there are not a lot of fanout groups and that this is not a high frequency call. The method assigns ids starting at zero and increases until it finds an unused id. It keeps track of the last assigned id, and uses it as a starting point to find new ids. Signed-off-by: Mike Maloney <maloney@google.com> Acked-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r--net/packet/af_packet.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 8489beff5c25..94052f42058b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1496,6 +1496,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
1496DEFINE_MUTEX(fanout_mutex); 1496DEFINE_MUTEX(fanout_mutex);
1497EXPORT_SYMBOL_GPL(fanout_mutex); 1497EXPORT_SYMBOL_GPL(fanout_mutex);
1498static LIST_HEAD(fanout_list); 1498static LIST_HEAD(fanout_list);
1499static u16 fanout_next_id;
1499 1500
1500static void __fanout_link(struct sock *sk, struct packet_sock *po) 1501static void __fanout_link(struct sock *sk, struct packet_sock *po)
1501{ 1502{
@@ -1629,6 +1630,36 @@ static void fanout_release_data(struct packet_fanout *f)
1629 }; 1630 };
1630} 1631}
1631 1632
1633static bool __fanout_id_is_free(struct sock *sk, u16 candidate_id)
1634{
1635 struct packet_fanout *f;
1636
1637 list_for_each_entry(f, &fanout_list, list) {
1638 if (f->id == candidate_id &&
1639 read_pnet(&f->net) == sock_net(sk)) {
1640 return false;
1641 }
1642 }
1643 return true;
1644}
1645
1646static bool fanout_find_new_id(struct sock *sk, u16 *new_id)
1647{
1648 u16 id = fanout_next_id;
1649
1650 do {
1651 if (__fanout_id_is_free(sk, id)) {
1652 *new_id = id;
1653 fanout_next_id = id + 1;
1654 return true;
1655 }
1656
1657 id++;
1658 } while (id != fanout_next_id);
1659
1660 return false;
1661}
1662
1632static int fanout_add(struct sock *sk, u16 id, u16 type_flags) 1663static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
1633{ 1664{
1634 struct packet_rollover *rollover = NULL; 1665 struct packet_rollover *rollover = NULL;
@@ -1676,6 +1707,19 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
1676 po->rollover = rollover; 1707 po->rollover = rollover;
1677 } 1708 }
1678 1709
1710 if (type_flags & PACKET_FANOUT_FLAG_UNIQUEID) {
1711 if (id != 0) {
1712 err = -EINVAL;
1713 goto out;
1714 }
1715 if (!fanout_find_new_id(sk, &id)) {
1716 err = -ENOMEM;
1717 goto out;
1718 }
1719 /* ephemeral flag for the first socket in the group: drop it */
1720 flags &= ~(PACKET_FANOUT_FLAG_UNIQUEID >> 8);
1721 }
1722
1679 match = NULL; 1723 match = NULL;
1680 list_for_each_entry(f, &fanout_list, list) { 1724 list_for_each_entry(f, &fanout_list, list) {
1681 if (f->id == id && 1725 if (f->id == id &&