public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net] bonding: Fix header_ops type confusion
@ 2025-05-26  5:08 戸田晃太
  2025-05-26  8:23 ` Eric Dumazet
  0 siblings, 1 reply; 16+ messages in thread
From: 戸田晃太 @ 2025-05-26  5:08 UTC (permalink / raw)
  To: 戸田晃太
  Cc: 小池悠生, netdev, linux-kernel, pabeni,
	edumazet

In bond_setup_by_slave(), the slave’s header_ops are unconditionally
copied into the bonding device. As a result, the bonding device may invoke
the slave-specific header operations on itself, causing
netdev_priv(bond_dev) (a struct bonding) to be incorrectly interpreted
as the slave's private-data type.

This type-confusion bug can lead to out-of-bounds writes into the skb,
resulting in memory corruption.

This patch adds two members to struct bonding, bond_header_ops and
header_slave_dev, to avoid type-confusion while keeping track of the
slave's header_ops.

Fixes: 1284cd3a2b740 (bonding: two small fixes for IPoIB support)
Signed-off-by: Kota Toda <kota.toda@gmo-cybersecurity.com>
Signed-off-by: Yuki Koike <yuki.koike@gmo-cybersecurity.com>
Co-Developed-by: Yuki Koike <yuki.koike@gmo-cybersecurity.com>
Reviewed-by: Paolo Abeni <pabeni@redhat.com>
Reported-by: Kota Toda <kota.toda@gmo-cybersecurity.com>
---
 drivers/net/bonding/bond_main.c | 61
++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/net/bonding.h           |  5 +++++
 2 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8ea183da8d53..690f3e0971d0 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1619,14 +1619,65 @@ static void bond_compute_features(struct bonding *bond)
     netdev_change_features(bond_dev);
 }

+static int bond_hard_header(struct sk_buff *skb, struct net_device *dev,
+        unsigned short type, const void *daddr,
+        const void *saddr, unsigned int len)
+{
+    struct bonding *bond = netdev_priv(dev);
+    struct net_device *slave_dev;
+
+    slave_dev = bond->header_slave_dev;
+
+    return dev_hard_header(skb, slave_dev, type, daddr, saddr, len);
+}
+
+static void bond_header_cache_update(struct hh_cache *hh, const
struct net_device *dev,
+        const unsigned char *haddr)
+{
+    const struct bonding *bond = netdev_priv(dev);
+    struct net_device *slave_dev;
+
+    slave_dev = bond->header_slave_dev;
+
+    if (!slave_dev->header_ops || !slave_dev->header_ops->cache_update)
+        return;
+
+    slave_dev->header_ops->cache_update(hh, slave_dev, haddr);
+}
+
 static void bond_setup_by_slave(struct net_device *bond_dev,
                 struct net_device *slave_dev)
 {
+    struct bonding *bond = netdev_priv(bond_dev);
     bool was_up = !!(bond_dev->flags & IFF_UP);

     dev_close(bond_dev);

-    bond_dev->header_ops        = slave_dev->header_ops;
+    /* Some functions are given dev as an argument
+     * while others not. When dev is not given, we cannot
+     * find out what is the slave device through struct bonding
+     * (the private data of bond_dev). Therefore, we need a raw
+     * header_ops variable instead of its pointer to const header_ops
+     * and assign slave's functions directly.
+     * For the other case, we set the wrapper functions that pass
+     * slave_dev to the wrapped functions.
+     */
+    bond->bond_header_ops.create = bond_hard_header;
+    bond->bond_header_ops.cache_update = bond_header_cache_update;
+    if (slave_dev->header_ops) {
+        bond->bond_header_ops.parse = slave_dev->header_ops->parse;
+        bond->bond_header_ops.cache = slave_dev->header_ops->cache;
+        bond->bond_header_ops.validate = slave_dev->header_ops->validate;
+        bond->bond_header_ops.parse_protocol =
slave_dev->header_ops->parse_protocol;
+    } else {
+        bond->bond_header_ops.parse = NULL;
+        bond->bond_header_ops.cache = NULL;
+        bond->bond_header_ops.validate = NULL;
+        bond->bond_header_ops.parse_protocol = NULL;
+    }
+
+    bond->header_slave_dev      = slave_dev;
+    bond_dev->header_ops        = &bond->bond_header_ops;

     bond_dev->type            = slave_dev->type;
     bond_dev->hard_header_len   = slave_dev->hard_header_len;
@@ -2676,6 +2727,14 @@ static int bond_release_and_destroy(struct
net_device *bond_dev,
     struct bonding *bond = netdev_priv(bond_dev);
     int ret;

+    /* If slave_dev is the earliest registered one, we must clear
+     * the variables related to header_ops to avoid dangling pointer.
+     */
+    if (bond->header_slave_dev == slave_dev) {
+        bond->header_slave_dev = NULL;
+        bond_dev->header_ops = NULL;
+    }
+
     ret = __bond_release_one(bond_dev, slave_dev, false, true);
     if (ret == 0 && !bond_has_slaves(bond) &&
         bond_dev->reg_state != NETREG_UNREGISTERING) {
diff --git a/include/net/bonding.h b/include/net/bonding.h
index 95f67b308c19..cf8206187ce9 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -215,6 +215,11 @@ struct bond_ipsec {
  */
 struct bonding {
     struct   net_device *dev; /* first - useful for panic debug */
+    struct   net_device *header_slave_dev;  /* slave net_device for
header_ops */
+    /* maintained as a non-const variable
+     * because bond's header_ops should change depending on slaves.
+     */
+    struct   header_ops bond_header_ops;
     struct   slave __rcu *curr_active_slave;
     struct   slave __rcu *current_arp_slave;
     struct   slave __rcu *primary_slave;

^ permalink raw reply related	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-02-06  4:02 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-26  5:08 [PATCH net] bonding: Fix header_ops type confusion 戸田晃太
2025-05-26  8:23 ` Eric Dumazet
2025-05-28 14:35   ` 戸田晃太
2025-05-28 15:10     ` Eric Dumazet
2025-06-06  7:16       ` 戸田晃太
2025-12-22  8:20       ` 小池悠生
2026-01-15 10:33         ` 戸田晃太
2026-01-15 11:06           ` Eric Dumazet
2026-01-19  5:36             ` 戸田晃太
2026-01-19  9:30               ` Eric Dumazet
2026-01-28 10:46                 ` 戸田晃太
2026-02-02 17:11                   ` Eric Dumazet
2026-02-05 10:56                     ` [PATCH net 0/2] net: bonding: fix type-confusion in bonding header_ops 戸田晃太
2026-02-05 10:57                     ` [PATCH net 1/2] " 戸田晃太
2026-02-06  3:57                       ` Kuniyuki Iwashima
2026-02-05 10:58                     ` [PATCH net 2/2] net: add READ_ONCE for header_ops callbacks 戸田晃太

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox