Re: [PATCH batadv v2 5/5] batman-adv: v: stop OGMv2 on disabled interface
Yuan Tan <[email protected]>
| Newsgroups | org.open-mesh.lists.batman |
|---|---|
| Message-ID | <CAPuPA7KEnOyK1cs1T=pQo7fye2TeMPZZw_pBiMCpJoQ4eXAE5g@mail.gmail.com> |
On Wed, May 13, 2026 at 12:01 AM Sven Eckelmann <[email protected]> wrote: > > When a batadv_hard_iface is disabled, its mesh_iface pointer is set to > NULL. However, batadv_v_ogm_send_meshif() may still dispatch OGMs via > batadv_v_ogm_queue_on_if() for interfaces that have since lost their > mesh_iface association. This results in a NULL pointer dereference when > batadv_v_ogm_queue_on_if() unconditionally calls netdev_priv() on the > now NULL hard_iface->mesh_iface to retrieve the batadv_priv. > > It is necessary to ensure that the batadv_v_ogm_queue_on_if() checks that > it is using the same mesh_iface for which batadv_v_ogm_send_meshif() was > called. > > Cc: [email protected] > Fixes: 0da0035942d4 ("batman-adv: OGMv2 - add basic infrastructure") > Reported-by: Yuan Tan <[email protected]> > Reported-by: Yifan Wu <[email protected]> > Reported-by: Juefei Pu <[email protected]> > Reported-by: Xin Liu <[email protected]> > Signed-off-by: Sven Eckelmann <[email protected]> > --- > net/batman-adv/bat_v_ogm.c | 39 +++++++++++++++++++++++++++------------ > 1 file changed, 27 insertions(+), 12 deletions(-) > > diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c > index e3870492..0643a723 100644 > --- a/net/batman-adv/bat_v_ogm.c > +++ b/net/batman-adv/bat_v_ogm.c > @@ -113,14 +113,14 @@ static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv) > > /** > * batadv_v_ogm_send_to_if() - send a batman ogm using a given interface > + * @bat_priv: the bat priv with all the mesh interface information > * @skb: the OGM to send > * @hard_iface: the interface to use to send the OGM > */ > -static void batadv_v_ogm_send_to_if(struct sk_buff *skb, > +static void batadv_v_ogm_send_to_if(struct batadv_priv *bat_priv, > + struct sk_buff *skb, > struct batadv_hard_iface *hard_iface) > { > - struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); > - > if (hard_iface->if_status != BATADV_IF_ACTIVE) { > kfree_skb(skb); > return; > @@ -187,6 +187,7 @@ static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface) > > /** > * batadv_v_ogm_aggr_send() - flush & send aggregation queue > + * @bat_priv: the bat priv with all the mesh interface information > * @hard_iface: the interface with the aggregation queue to flush > * > * Aggregates all OGMv2 packets currently in the aggregation queue into a > @@ -196,7 +197,8 @@ static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface) > * > * Caller needs to hold the hard_iface->bat_v.aggr_list.lock. > */ > -static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface) > +static void batadv_v_ogm_aggr_send(struct batadv_priv *bat_priv, > + struct batadv_hard_iface *hard_iface) > { > unsigned int aggr_len = hard_iface->bat_v.aggr_len; > struct sk_buff *skb_aggr; > @@ -226,27 +228,32 @@ static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface) > consume_skb(skb); > } > > - batadv_v_ogm_send_to_if(skb_aggr, hard_iface); > + batadv_v_ogm_send_to_if(bat_priv, skb_aggr, hard_iface); > } > > /** > * batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface > + * @bat_priv: the bat priv with all the mesh interface information > * @skb: the OGM to queue > * @hard_iface: the interface to queue the OGM on > */ > -static void batadv_v_ogm_queue_on_if(struct sk_buff *skb, > +static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv, > + struct sk_buff *skb, > struct batadv_hard_iface *hard_iface) > { > - struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); > + if (hard_iface->mesh_iface != bat_priv->mesh_iface) { > + kfree_skb(skb); > + return; > + } > > if (!atomic_read(&bat_priv->aggregated_ogms)) { > - batadv_v_ogm_send_to_if(skb, hard_iface); > + batadv_v_ogm_send_to_if(bat_priv, skb, hard_iface); > return; > } > > spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); > if (!batadv_v_ogm_queue_left(skb, hard_iface)) > - batadv_v_ogm_aggr_send(hard_iface); > + batadv_v_ogm_aggr_send(bat_priv, hard_iface); > > hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb); > __skb_queue_tail(&hard_iface->bat_v.aggr_list, skb); > @@ -343,7 +350,7 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv) > break; > } > > - batadv_v_ogm_queue_on_if(skb_tmp, hard_iface); > + batadv_v_ogm_queue_on_if(bat_priv, skb_tmp, hard_iface); > batadv_hardif_put(hard_iface); > } > rcu_read_unlock(); > @@ -383,12 +390,20 @@ void batadv_v_ogm_aggr_work(struct work_struct *work) > { > struct batadv_hard_iface_bat_v *batv; > struct batadv_hard_iface *hard_iface; > + struct batadv_priv *bat_priv; > + struct net_device *meshif; > > batv = container_of(work, struct batadv_hard_iface_bat_v, aggr_wq.work); > hard_iface = container_of(batv, struct batadv_hard_iface, bat_v); > + meshif = hard_iface->mesh_iface; > + > + if (!meshif) > + return; > + > + bat_priv = netdev_priv(meshif); > > spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); > - batadv_v_ogm_aggr_send(hard_iface); > + batadv_v_ogm_aggr_send(bat_priv, hard_iface); > spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock); > > batadv_v_ogm_start_queue_timer(hard_iface); > @@ -578,7 +593,7 @@ static void batadv_v_ogm_forward(struct batadv_priv *bat_priv, > if_outgoing->net_dev->name, ntohl(ogm_forward->throughput), > ogm_forward->ttl, if_incoming->net_dev->name); > > - batadv_v_ogm_queue_on_if(skb, if_outgoing); > + batadv_v_ogm_queue_on_if(bat_priv, skb, if_outgoing); > > out: > batadv_orig_ifinfo_put(orig_ifinfo); > > -- > 2.47.3 > Reviewed-by: Yuan Tan <[email protected]>