* [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
@ 2026-08-24 2:18 Qihang
2026-08-24 2:18 ` [PATCH net 2/2] team: reject frames with insufficient headroom in team_header_create Qihang
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Qihang @ 2026-08-24 2:18 UTC (permalink / raw)
To: jv, jiri
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, willemb, netdev,
Qihang Tang, stable
From: Qihang Tang <q.h.hack.winter@gmail.com>
AF_PACKET SOCK_DGRAM sends reserve skb headroom from a snapshot of
bond_dev->hard_header_len. A concurrent bond type change can switch the
active slave to one with a larger hard_header_len between that snapshot
and bond_header_create(), so the slave's create() pushes or writes past
skb->head.
The hard_header_len snapshot series that fixed the SOCK_RAW send paths
deferred this SOCK_DGRAM race: dev->header_ops is the stable
bond_header_ops, so snapshotting header_ops in the caller does not help.
Reject the frame if skb headroom is smaller than the active slave's
hard_header_len, before delegating under the existing rcu_read_lock.
Fixes: 950803f72547 ("bonding: fix type confusion in bond_setup_by_slave()")
Cc: stable@vger.kernel.org
Cc: Willem de Bruijn <willemb@google.com>
Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
---
drivers/net/bonding/bond_main.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 522eab060f9e..9ec663610dfd 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1524,10 +1524,24 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
slave = rcu_dereference(bond->curr_active_slave);
if (slave) {
slave_ops = READ_ONCE(slave->dev->header_ops);
- if (slave_ops && slave_ops->create)
+ if (slave_ops && slave_ops->create) {
+ unsigned int hlen = READ_ONCE(slave->dev->hard_header_len);
+
+ /* Headroom was reserved from a snapshot of
+ * bond_dev->hard_header_len that may predate this
+ * slave (concurrent bond type change); reject if
+ * insufficient for the slave's create(), which
+ * pushes its own hlen.
+ */
+ if (skb_headroom(skb) < hlen) {
+ ret = -EINVAL;
+ goto unlock;
+ }
ret = slave_ops->create(skb, slave->dev,
type, daddr, saddr, len);
+ }
}
+unlock:
rcu_read_unlock();
return ret;
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net 2/2] team: reject frames with insufficient headroom in team_header_create
2026-08-24 2:18 [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create Qihang
@ 2026-08-24 2:18 ` Qihang
2026-08-26 2:02 ` [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create Willem de Bruijn
2026-08-27 1:10 ` Hangbin Liu
2 siblings, 0 replies; 11+ messages in thread
From: Qihang @ 2026-08-24 2:18 UTC (permalink / raw)
To: jv, jiri
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, willemb, netdev,
Qihang Tang, stable
From: Qihang Tang <q.h.hack.winter@gmail.com>
AF_PACKET SOCK_DGRAM sends reserve skb headroom from a snapshot of
team_dev->hard_header_len. A concurrent team type change can switch the
selected port to one with a larger hard_header_len between that snapshot
and team_header_create(), so the port's create() pushes or writes past
skb->head.
This is the same race as in bond_header_create(); the snapshot series
that fixed the SOCK_RAW send paths deferred it. dev->header_ops is the
stable team_header_ops, so snapshotting header_ops in the caller does
not help.
Reject the frame if skb headroom is smaller than the selected port's
hard_header_len, before delegating under the existing rcu_read_lock.
Fixes: 425000dbf173 ("team: fix header_ops type confusion with non-Ethernet ports")
Cc: stable@vger.kernel.org
Cc: Willem de Bruijn <willemb@google.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
---
drivers/net/team/team_core.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index feaa75fbf8fc..2742a4bfc9d0 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -2269,10 +2269,24 @@ static int team_header_create(struct sk_buff *skb, struct net_device *team_dev,
port = team_header_port_get_rcu(team, true);
if (port) {
port_ops = READ_ONCE(port->dev->header_ops);
- if (port_ops && port_ops->create)
+ if (port_ops && port_ops->create) {
+ unsigned int hlen = READ_ONCE(port->dev->hard_header_len);
+
+ /* Headroom was reserved from a snapshot of
+ * team_dev->hard_header_len that may predate this
+ * port (concurrent team type change); reject if
+ * insufficient for the port's create(), which
+ * pushes its own hlen.
+ */
+ if (skb_headroom(skb) < hlen) {
+ ret = -EINVAL;
+ goto unlock;
+ }
ret = port_ops->create(skb, port->dev,
type, daddr, saddr, len);
+ }
}
+unlock:
rcu_read_unlock();
return ret;
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-24 2:18 [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create Qihang
2026-08-24 2:18 ` [PATCH net 2/2] team: reject frames with insufficient headroom in team_header_create Qihang
@ 2026-08-26 2:02 ` Willem de Bruijn
2026-08-27 3:13 ` Qihang
2026-08-27 1:10 ` Hangbin Liu
2 siblings, 1 reply; 11+ messages in thread
From: Willem de Bruijn @ 2026-08-26 2:02 UTC (permalink / raw)
To: Qihang, jv, jiri
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, willemb, netdev,
Qihang Tang, stable
Qihang wrote:
> From: Qihang Tang <q.h.hack.winter@gmail.com>
Thanks for working on this Qihang.
Minor: a patch series should generally have a cover letter
> AF_PACKET SOCK_DGRAM sends reserve skb headroom from a snapshot of
> bond_dev->hard_header_len. A concurrent bond type change can switch the
> active slave to one with a larger hard_header_len between that snapshot
> and bond_header_create(), so the slave's create() pushes or writes past
> skb->head.
Are we certain that bond and team are the only devices that implement
header_ops->create?
> The hard_header_len snapshot series that fixed the SOCK_RAW send paths
> deferred this SOCK_DGRAM race: dev->header_ops is the stable
> bond_header_ops, so snapshotting header_ops in the caller does not help.
>
> Reject the frame if skb headroom is smaller than the active slave's
> hard_header_len, before delegating under the existing rcu_read_lock.
>
> Fixes: 950803f72547 ("bonding: fix type confusion in bond_setup_by_slave()")
What's the rationale behind blaming this SHA1?
> Cc: stable@vger.kernel.org
> Cc: Willem de Bruijn <willemb@google.com>
> Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
> ---
> drivers/net/bonding/bond_main.c | 16 +++++++++++++++-
> 1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 522eab060f9e..9ec663610dfd 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -1524,10 +1524,24 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
> slave = rcu_dereference(bond->curr_active_slave);
> if (slave) {
> slave_ops = READ_ONCE(slave->dev->header_ops);
> - if (slave_ops && slave_ops->create)
> + if (slave_ops && slave_ops->create) {
> + unsigned int hlen = READ_ONCE(slave->dev->hard_header_len);
> +
> + /* Headroom was reserved from a snapshot of
> + * bond_dev->hard_header_len that may predate this
> + * slave (concurrent bond type change); reject if
> + * insufficient for the slave's create(), which
> + * pushes its own hlen.
> + */
> + if (skb_headroom(skb) < hlen) {
> + ret = -EINVAL;
> + goto unlock;
> + }
> ret = slave_ops->create(skb, slave->dev,
> type, daddr, saddr, len);
> + }
Ideally we could fix this in dev_hard_header or PF_PACKET itself,
rather than in each implementation that's in scope.
But there seems no way around holding this rcu reference on the slave
device while re-checking.
> }
> +unlock:
> rcu_read_unlock();
> return ret;
> }
> --
> 2.50.1 (Apple Git-155)
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-24 2:18 [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create Qihang
2026-08-24 2:18 ` [PATCH net 2/2] team: reject frames with insufficient headroom in team_header_create Qihang
2026-08-26 2:02 ` [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create Willem de Bruijn
@ 2026-08-27 1:10 ` Hangbin Liu
2026-08-27 3:25 ` Qihang
2 siblings, 1 reply; 11+ messages in thread
From: Hangbin Liu @ 2026-08-27 1:10 UTC (permalink / raw)
To: Qihang
Cc: jv, jiri, andrew+netdev, davem, edumazet, kuba, pabeni, willemb,
netdev, stable
Hi Qinghang,
On Mon, Aug 24, 2026 at 10:18:01AM +0800, Qihang wrote:
> From: Qihang Tang <q.h.hack.winter@gmail.com>
>
> AF_PACKET SOCK_DGRAM sends reserve skb headroom from a snapshot of
> bond_dev->hard_header_len. A concurrent bond type change can switch the
> active slave to one with a larger hard_header_len between that snapshot
> and bond_header_create(), so the slave's create() pushes or writes past
> skb->head.
How can bonding change its device type while still sending skbs?
Bonding does not allow enslaving devices of different types. We have
to remove all slaves before changing its type.
Thanks
Hangbin
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-26 2:02 ` [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create Willem de Bruijn
@ 2026-08-27 3:13 ` Qihang
2026-08-27 5:10 ` Jiayuan Chen
2026-08-27 21:37 ` Willem de Bruijn
0 siblings, 2 replies; 11+ messages in thread
From: Qihang @ 2026-08-27 3:13 UTC (permalink / raw)
To: Willem de Bruijn
Cc: jv, jiri, andrew+netdev, davem, edumazet, kuba, pabeni, willemb,
netdev, stable, Hangbin Liu
Hi Willem,
I'll resend this as v2 with a cover letter.
On scope: I grepped every header_ops->create. Five devices delegate to a
lower device (bond, team, macvlan, ipvlan, 6lowpan), but only bond and
team re-select that lower device under RCU -- the rest bind it at netdev
creation. So bond and team are the full scope.
Re Fixes: I used 950803f because it introduced bond_header_create (where
this check lives); before it the type-confusion BUG masked this race.
Happy to point at 1284cd3a2b74 instead if you prefer.
On the fix location, I'd rather get your read before writing more. The
options I see:
1. per-wrapper headroom reject in bond/team only -- small, safe,
backport-friendly, but not generic (the next stacked device needs
its own).
2. central check in dev_hard_header on dev->hard_header_len -- one
place, but I think it's unsafe for bond: bond_dev->hard_header_len
only follows the first slave (bond_setup_by_slave),
bond_change_active_slave flips curr_active_slave without touching
it, and same-type slaves can have different hard_header_len (two GRE
tunnels). So it can under-reject. Would need bond to maintain
hard_header_len differently first.
3. resolve the effective {dev, ops, hard_header_len} as one RCU triple
via a generic callback, so the caller never cares which subordinate
the master picks. Truly generic and race-free, but it's a new ndo --
net-next material, awkward for stable backport.
4. make header_ops->create() take an explicit headroom contract and
fail cleanly instead of pushing blind -- cleanest long-term, but
touches every create() in the tree. Too heavy for now.
My v1 is option 1 (per-wrapper). Want one of these, a combination,
or something else entirely?
Thanks,
Qihang
On Wed, Aug 26, 2026 at 10:02 AM Willem de Bruijn
<willemdebruijn.kernel@gmail.com> wrote:
>
> Qihang wrote:
> > From: Qihang Tang <q.h.hack.winter@gmail.com>
>
> Thanks for working on this Qihang.
>
> Minor: a patch series should generally have a cover letter
>
> > AF_PACKET SOCK_DGRAM sends reserve skb headroom from a snapshot of
> > bond_dev->hard_header_len. A concurrent bond type change can switch the
> > active slave to one with a larger hard_header_len between that snapshot
> > and bond_header_create(), so the slave's create() pushes or writes past
> > skb->head.
>
> Are we certain that bond and team are the only devices that implement
> header_ops->create?
>
> > The hard_header_len snapshot series that fixed the SOCK_RAW send paths
> > deferred this SOCK_DGRAM race: dev->header_ops is the stable
> > bond_header_ops, so snapshotting header_ops in the caller does not help.
> >
> > Reject the frame if skb headroom is smaller than the active slave's
> > hard_header_len, before delegating under the existing rcu_read_lock.
> >
> > Fixes: 950803f72547 ("bonding: fix type confusion in bond_setup_by_slave()")
>
> What's the rationale behind blaming this SHA1?
>
> > Cc: stable@vger.kernel.org
> > Cc: Willem de Bruijn <willemb@google.com>
> > Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
> > ---
> > drivers/net/bonding/bond_main.c | 16 +++++++++++++++-
> > 1 file changed, 15 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> > index 522eab060f9e..9ec663610dfd 100644
> > --- a/drivers/net/bonding/bond_main.c
> > +++ b/drivers/net/bonding/bond_main.c
> > @@ -1524,10 +1524,24 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
> > slave = rcu_dereference(bond->curr_active_slave);
> > if (slave) {
> > slave_ops = READ_ONCE(slave->dev->header_ops);
> > - if (slave_ops && slave_ops->create)
> > + if (slave_ops && slave_ops->create) {
> > + unsigned int hlen = READ_ONCE(slave->dev->hard_header_len);
> > +
> > + /* Headroom was reserved from a snapshot of
> > + * bond_dev->hard_header_len that may predate this
> > + * slave (concurrent bond type change); reject if
> > + * insufficient for the slave's create(), which
> > + * pushes its own hlen.
> > + */
> > + if (skb_headroom(skb) < hlen) {
> > + ret = -EINVAL;
> > + goto unlock;
> > + }
> > ret = slave_ops->create(skb, slave->dev,
> > type, daddr, saddr, len);
> > + }
>
> Ideally we could fix this in dev_hard_header or PF_PACKET itself,
> rather than in each implementation that's in scope.
>
> But there seems no way around holding this rcu reference on the slave
> device while re-checking.
>
>
>
> > }
> > +unlock:
> > rcu_read_unlock();
> > return ret;
> > }
> > --
> > 2.50.1 (Apple Git-155)
> >
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-27 1:10 ` Hangbin Liu
@ 2026-08-27 3:25 ` Qihang
0 siblings, 0 replies; 11+ messages in thread
From: Qihang @ 2026-08-27 3:25 UTC (permalink / raw)
To: Hangbin Liu
Cc: jv, jiri, andrew+netdev, davem, edumazet, kuba, pabeni, willemb,
netdev, stable
Hi Hangbin,
Thanks for the catch. You're right, my wording was inaccurate. This is not
about an active slave switch or changing the bond type while sending.
The issue is a hard_header_len update race in bond_setup_by_slave(). An
in-flight AF_PACKET SOCK_DGRAM send can snapshot the old
bond_dev->hard_header_len
for skb headroom reservation, then bond_setup_by_slave() updates it and
installs a new active slave. The existing send path can continue after this
because dev_close()/dev_open() does not synchronize with already running
packet_snd().
Later bond_header_create() uses the new active slave's hard_header_len, which
may be larger than the reserved headroom.
For the first-slave case, the bond can be slaveless before enslaving, so
removing existing slaves does not prevent this window.
Thanks,
Qihang
On Thu, Aug 27, 2026 at 9:10 AM Hangbin Liu <hangbin.liu@linux.dev> wrote:
>
> Hi Qinghang,
>
> On Mon, Aug 24, 2026 at 10:18:01AM +0800, Qihang wrote:
> > From: Qihang Tang <q.h.hack.winter@gmail.com>
> >
> > AF_PACKET SOCK_DGRAM sends reserve skb headroom from a snapshot of
> > bond_dev->hard_header_len. A concurrent bond type change can switch the
> > active slave to one with a larger hard_header_len between that snapshot
> > and bond_header_create(), so the slave's create() pushes or writes past
> > skb->head.
>
> How can bonding change its device type while still sending skbs?
> Bonding does not allow enslaving devices of different types. We have
> to remove all slaves before changing its type.
>
> Thanks
> Hangbin
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-27 3:13 ` Qihang
@ 2026-08-27 5:10 ` Jiayuan Chen
2026-08-27 21:37 ` Willem de Bruijn
1 sibling, 0 replies; 11+ messages in thread
From: Jiayuan Chen @ 2026-08-27 5:10 UTC (permalink / raw)
To: Qihang, Willem de Bruijn
Cc: jv, jiri, andrew+netdev, davem, edumazet, kuba, pabeni, willemb,
netdev, stable, Hangbin Liu
在 8/27/26 11:13 AM, Qihang 写道:
> Hi Willem,
>
> I'll resend this as v2 with a cover letter.
>
> On scope: I grepped every header_ops->create. Five devices delegate to a
> lower device (bond, team, macvlan, ipvlan, 6lowpan), but only bond and
> team re-select that lower device under RCU -- the rest bind it at netdev
> creation. So bond and team are the full scope.
>
> Re Fixes: I used 950803f because it introduced bond_header_create (where
> this check lives); before it the type-confusion BUG masked this race.
> Happy to point at 1284cd3a2b74 instead if you prefer.
Can you check whether IPoIB + bond hits the issue you describe? That combo
isn't affected by 950803f (ipoib_hard_header doesn't use netdev_priv, no
type
confusion), so if it overflows, the Fixes tag shouldn't point to 950803f.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-27 3:13 ` Qihang
2026-08-27 5:10 ` Jiayuan Chen
@ 2026-08-27 21:37 ` Willem de Bruijn
2026-08-28 1:12 ` Hangbin Liu
1 sibling, 1 reply; 11+ messages in thread
From: Willem de Bruijn @ 2026-08-27 21:37 UTC (permalink / raw)
To: Qihang, Willem de Bruijn
Cc: jv, jiri, andrew+netdev, davem, edumazet, kuba, pabeni, willemb,
netdev, stable, Hangbin Liu
Qihang wrote:
> Hi Willem,
>
> I'll resend this as v2 with a cover letter.
>
> On scope: I grepped every header_ops->create. Five devices delegate to a
> lower device (bond, team, macvlan, ipvlan, 6lowpan), but only bond and
> team re-select that lower device under RCU -- the rest bind it at netdev
> creation. So bond and team are the full scope.
>
> Re Fixes: I used 950803f because it introduced bond_header_create (where
> this check lives); before it the type-confusion BUG masked this race.
> Happy to point at 1284cd3a2b74 instead if you prefer.
>
> On the fix location, I'd rather get your read before writing more. The
> options I see:
>
> 1. per-wrapper headroom reject in bond/team only -- small, safe,
> backport-friendly, but not generic (the next stacked device needs
> its own).
>
> 2. central check in dev_hard_header on dev->hard_header_len -- one
> place, but I think it's unsafe for bond: bond_dev->hard_header_len
> only follows the first slave (bond_setup_by_slave),
> bond_change_active_slave flips curr_active_slave without touching
> it, and same-type slaves can have different hard_header_len (two GRE
> tunnels). So it can under-reject. Would need bond to maintain
> hard_header_len differently first.
>
> 3. resolve the effective {dev, ops, hard_header_len} as one RCU triple
> via a generic callback, so the caller never cares which subordinate
> the master picks. Truly generic and race-free, but it's a new ndo --
> net-next material, awkward for stable backport.
>
> 4. make header_ops->create() take an explicit headroom contract and
> fail cleanly instead of pushing blind -- cleanest long-term, but
> touches every create() in the tree. Too heavy for now.
>
> My v1 is option 1 (per-wrapper). Want one of these, a combination,
> or something else entirely?
Thanks for the analysis.
I agree that 3 nd 4 are too invasive for the scope of the bug.
It's a bit odd that bond and team just take the hard_header_len of the
first slave. And that bond_create_header just passes to
curr_active_slave, while various bond modes like LAG will have
multiple concurrently active slaves.
That indicates that the intent is for all slaves to have the same
header length and header_ops->create callback.
But this is not enforced.
Given that this seems a bond specific issue, that was copied in teams,
fair to solve it there. Doubly so as due to RCU we have no easy path
to solve it elsewhere. So +1.
> Thanks,
> Qihang
>
>
> On Wed, Aug 26, 2026 at 10:02 AM Willem de Bruijn
> <willemdebruijn.kernel@gmail.com> wrote:
> >
> > Qihang wrote:
> > > From: Qihang Tang <q.h.hack.winter@gmail.com>
> >
> > Thanks for working on this Qihang.
> >
> > Minor: a patch series should generally have a cover letter
> >
> > > AF_PACKET SOCK_DGRAM sends reserve skb headroom from a snapshot of
> > > bond_dev->hard_header_len. A concurrent bond type change can switch the
> > > active slave to one with a larger hard_header_len between that snapshot
> > > and bond_header_create(), so the slave's create() pushes or writes past
> > > skb->head.
> >
> > Are we certain that bond and team are the only devices that implement
> > header_ops->create?
> >
> > > The hard_header_len snapshot series that fixed the SOCK_RAW send paths
> > > deferred this SOCK_DGRAM race: dev->header_ops is the stable
> > > bond_header_ops, so snapshotting header_ops in the caller does not help.
> > >
> > > Reject the frame if skb headroom is smaller than the active slave's
> > > hard_header_len, before delegating under the existing rcu_read_lock.
> > >
> > > Fixes: 950803f72547 ("bonding: fix type confusion in bond_setup_by_slave()")
> >
> > What's the rationale behind blaming this SHA1?
> >
> > > Cc: stable@vger.kernel.org
> > > Cc: Willem de Bruijn <willemb@google.com>
> > > Signed-off-by: Qihang Tang <q.h.hack.winter@gmail.com>
> > > ---
> > > drivers/net/bonding/bond_main.c | 16 +++++++++++++++-
> > > 1 file changed, 15 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> > > index 522eab060f9e..9ec663610dfd 100644
> > > --- a/drivers/net/bonding/bond_main.c
> > > +++ b/drivers/net/bonding/bond_main.c
> > > @@ -1524,10 +1524,24 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
> > > slave = rcu_dereference(bond->curr_active_slave);
> > > if (slave) {
> > > slave_ops = READ_ONCE(slave->dev->header_ops);
> > > - if (slave_ops && slave_ops->create)
> > > + if (slave_ops && slave_ops->create) {
> > > + unsigned int hlen = READ_ONCE(slave->dev->hard_header_len);
> > > +
> > > + /* Headroom was reserved from a snapshot of
> > > + * bond_dev->hard_header_len that may predate this
> > > + * slave (concurrent bond type change); reject if
> > > + * insufficient for the slave's create(), which
> > > + * pushes its own hlen.
> > > + */
> > > + if (skb_headroom(skb) < hlen) {
> > > + ret = -EINVAL;
> > > + goto unlock;
> > > + }
> > > ret = slave_ops->create(skb, slave->dev,
> > > type, daddr, saddr, len);
> > > + }
> >
> > Ideally we could fix this in dev_hard_header or PF_PACKET itself,
> > rather than in each implementation that's in scope.
> >
> > But there seems no way around holding this rcu reference on the slave
> > device while re-checking.
> >
> >
> >
> > > }
> > > +unlock:
> > > rcu_read_unlock();
> > > return ret;
> > > }
> > > --
> > > 2.50.1 (Apple Git-155)
> > >
> >
> >
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-27 21:37 ` Willem de Bruijn
@ 2026-08-28 1:12 ` Hangbin Liu
2026-08-28 2:43 ` Willem de Bruijn
0 siblings, 1 reply; 11+ messages in thread
From: Hangbin Liu @ 2026-08-28 1:12 UTC (permalink / raw)
To: Willem de Bruijn
Cc: Qihang, jv, jiri, andrew+netdev, davem, edumazet, kuba, pabeni,
willemb, netdev, stable
On Thu, Aug 27, 2026 at 05:37:09PM -0400, Willem de Bruijn wrote:
> Qihang wrote:
> > Hi Willem,
> >
> > I'll resend this as v2 with a cover letter.
> >
> > On scope: I grepped every header_ops->create. Five devices delegate to a
> > lower device (bond, team, macvlan, ipvlan, 6lowpan), but only bond and
> > team re-select that lower device under RCU -- the rest bind it at netdev
> > creation. So bond and team are the full scope.
> >
> > Re Fixes: I used 950803f because it introduced bond_header_create (where
> > this check lives); before it the type-confusion BUG masked this race.
> > Happy to point at 1284cd3a2b74 instead if you prefer.
> >
> > On the fix location, I'd rather get your read before writing more. The
> > options I see:
> >
> > 1. per-wrapper headroom reject in bond/team only -- small, safe,
> > backport-friendly, but not generic (the next stacked device needs
> > its own).
> >
> > 2. central check in dev_hard_header on dev->hard_header_len -- one
> > place, but I think it's unsafe for bond: bond_dev->hard_header_len
> > only follows the first slave (bond_setup_by_slave),
> > bond_change_active_slave flips curr_active_slave without touching
> > it, and same-type slaves can have different hard_header_len (two GRE
> > tunnels). So it can under-reject. Would need bond to maintain
> > hard_header_len differently first.
> >
> > 3. resolve the effective {dev, ops, hard_header_len} as one RCU triple
> > via a generic callback, so the caller never cares which subordinate
> > the master picks. Truly generic and race-free, but it's a new ndo --
> > net-next material, awkward for stable backport.
> >
> > 4. make header_ops->create() take an explicit headroom contract and
> > fail cleanly instead of pushing blind -- cleanest long-term, but
> > touches every create() in the tree. Too heavy for now.
> >
> > My v1 is option 1 (per-wrapper). Want one of these, a combination,
> > or something else entirely?
>
> Thanks for the analysis.
>
> I agree that 3 nd 4 are too invasive for the scope of the bug.
>
> It's a bit odd that bond and team just take the hard_header_len of the
> first slave. And that bond_create_header just passes to
Actually, bond will use the max hard_header_len of all slaves, see
netdev_compute_master_upper_features()
> curr_active_slave, while various bond modes like LAG will have
> multiple concurrently active slaves.
>
> That indicates that the intent is for all slaves to have the same
> header length and header_ops->create callback.
And here seem you want to all saves also sync the header length?
I'm not sure if we should/could do this in the same function
netdev_compute_master_upper_features().
Thanks
Hangbin
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-28 1:12 ` Hangbin Liu
@ 2026-08-28 2:43 ` Willem de Bruijn
2026-08-28 6:07 ` Qihang
0 siblings, 1 reply; 11+ messages in thread
From: Willem de Bruijn @ 2026-08-28 2:43 UTC (permalink / raw)
To: Hangbin Liu, Willem de Bruijn
Cc: Qihang, jv, jiri, andrew+netdev, davem, edumazet, kuba, pabeni,
willemb, netdev, stable
Hangbin Liu wrote:
> On Thu, Aug 27, 2026 at 05:37:09PM -0400, Willem de Bruijn wrote:
> > Qihang wrote:
> > > Hi Willem,
> > >
> > > I'll resend this as v2 with a cover letter.
> > >
> > > On scope: I grepped every header_ops->create. Five devices delegate to a
> > > lower device (bond, team, macvlan, ipvlan, 6lowpan), but only bond and
> > > team re-select that lower device under RCU -- the rest bind it at netdev
> > > creation. So bond and team are the full scope.
> > >
> > > Re Fixes: I used 950803f because it introduced bond_header_create (where
> > > this check lives); before it the type-confusion BUG masked this race.
> > > Happy to point at 1284cd3a2b74 instead if you prefer.
> > >
> > > On the fix location, I'd rather get your read before writing more. The
> > > options I see:
> > >
> > > 1. per-wrapper headroom reject in bond/team only -- small, safe,
> > > backport-friendly, but not generic (the next stacked device needs
> > > its own).
> > >
> > > 2. central check in dev_hard_header on dev->hard_header_len -- one
> > > place, but I think it's unsafe for bond: bond_dev->hard_header_len
> > > only follows the first slave (bond_setup_by_slave),
> > > bond_change_active_slave flips curr_active_slave without touching
> > > it, and same-type slaves can have different hard_header_len (two GRE
> > > tunnels). So it can under-reject. Would need bond to maintain
> > > hard_header_len differently first.
> > >
> > > 3. resolve the effective {dev, ops, hard_header_len} as one RCU triple
> > > via a generic callback, so the caller never cares which subordinate
> > > the master picks. Truly generic and race-free, but it's a new ndo --
> > > net-next material, awkward for stable backport.
> > >
> > > 4. make header_ops->create() take an explicit headroom contract and
> > > fail cleanly instead of pushing blind -- cleanest long-term, but
> > > touches every create() in the tree. Too heavy for now.
> > >
> > > My v1 is option 1 (per-wrapper). Want one of these, a combination,
> > > or something else entirely?
> >
> > Thanks for the analysis.
> >
> > I agree that 3 nd 4 are too invasive for the scope of the bug.
> >
> > It's a bit odd that bond and team just take the hard_header_len of the
> > first slave. And that bond_create_header just passes to
>
> Actually, bond will use the max hard_header_len of all slaves, see
>
> netdev_compute_master_upper_features()
Awesome. That should address the issue.
>
> > curr_active_slave, while various bond modes like LAG will have
> > multiple concurrently active slaves.
> >
> > That indicates that the intent is for all slaves to have the same
> > header length and header_ops->create callback.
>
> And here seem you want to all saves also sync the header length?
>
> I'm not sure if we should/could do this in the same function
> netdev_compute_master_upper_features().
As long as the header length allocated is the max of all slaves'
requirements, no need to check again here, I think.
> Thanks
> Hangbin
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create
2026-08-28 2:43 ` Willem de Bruijn
@ 2026-08-28 6:07 ` Qihang
0 siblings, 0 replies; 11+ messages in thread
From: Qihang @ 2026-08-28 6:07 UTC (permalink / raw)
To: Willem de Bruijn
Cc: Hangbin Liu, jv, jiri, andrew+netdev, davem, edumazet, kuba,
pabeni, willemb, netdev, stable
Yeah, agreed on steady state.
One thing to flag: packet_snd snapshots dev->hard_header_len at
af_packet.c:3023 (no lock) but pushes the header at :3059 onto whatever
curr_active_slave is then. A concurrent enslave that bumps it in between
-- first non-Ethernet slave 14->24, or a bigger-header failover -- can
leave the in-flight frame short and trip skb_under_panic (oops/panic,
not silent corruption; local DoS for a privileged user).
Happy to drop v1, or hand over the create-time check if you want it closed.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-08-28 6:07 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-24 2:18 [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create Qihang
2026-08-24 2:18 ` [PATCH net 2/2] team: reject frames with insufficient headroom in team_header_create Qihang
2026-08-26 2:02 ` [PATCH net 1/2] bonding: reject frames with insufficient headroom in bond_header_create Willem de Bruijn
2026-08-27 3:13 ` Qihang
2026-08-27 5:10 ` Jiayuan Chen
2026-08-27 21:37 ` Willem de Bruijn
2026-08-28 1:12 ` Hangbin Liu
2026-08-28 2:43 ` Willem de Bruijn
2026-08-28 6:07 ` Qihang
2026-08-27 1:10 ` Hangbin Liu
2026-08-27 3:25 ` Qihang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox