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]>

Reply via email to