Commit 564d74d6 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'batadv-net-pullrequest-20241210' of git://git.open-mesh.org/linux-merge

Simon Wunderlich says:

====================
Here are some batman-adv bugfixes:

 - fix TT unitialized data and size limit issues, by Remi Pommarel
  (3 patches)

* tag 'batadv-net-pullrequest-20241210' of git://git.open-mesh.org/linux-merge:
  batman-adv: Do not let TT changes list grows indefinitely
  batman-adv: Remove uninitialized data in full table TT response
  batman-adv: Do not send uninitialized TT changes
====================

Link: https://patch.msgid.link/20241210135024.39068-1-sw@simonwunderlich.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents acfcdb78 fff8f17c
Loading
Loading
Loading
Loading
+40 −18
Original line number Diff line number Diff line
@@ -948,16 +948,25 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
	int tt_diff_len, tt_change_len = 0;
	int tt_diff_entries_num = 0;
	int tt_diff_entries_count = 0;
	bool drop_changes = false;
	size_t tt_extra_len = 0;
	u16 tvlv_len;

	tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes);
	tt_diff_len = batadv_tt_len(tt_diff_entries_num);

	/* if we have too many changes for one packet don't send any
	 * and wait for the tt table request which will be fragmented
	 * and wait for the tt table request so we can reply with the full
	 * (fragmented) table.
	 *
	 * The local change history should still be cleaned up so the next
	 * TT round can start again with a clean state.
	 */
	if (tt_diff_len > bat_priv->soft_iface->mtu)
	if (tt_diff_len > bat_priv->soft_iface->mtu) {
		tt_diff_len = 0;
		tt_diff_entries_num = 0;
		drop_changes = true;
	}

	tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
						     &tt_change, &tt_diff_len);
@@ -966,7 +975,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)

	tt_data->flags = BATADV_TT_OGM_DIFF;

	if (tt_diff_len == 0)
	if (!drop_changes && tt_diff_len == 0)
		goto container_register;

	spin_lock_bh(&bat_priv->tt.changes_list_lock);
@@ -985,6 +994,9 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
	}
	spin_unlock_bh(&bat_priv->tt.changes_list_lock);

	tt_extra_len = batadv_tt_len(tt_diff_entries_num -
				     tt_diff_entries_count);

	/* Keep the buffer for possible tt_request */
	spin_lock_bh(&bat_priv->tt.last_changeset_lock);
	kfree(bat_priv->tt.last_changeset);
@@ -993,6 +1005,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
	tt_change_len = batadv_tt_len(tt_diff_entries_count);
	/* check whether this new OGM has no changes due to size problems */
	if (tt_diff_entries_count > 0) {
		tt_diff_len -= tt_extra_len;
		/* if kmalloc() fails we will reply with the full table
		 * instead of providing the diff
		 */
@@ -1005,6 +1018,8 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
	}
	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);

	/* Remove extra packet space for OGM */
	tvlv_len -= tt_extra_len;
container_register:
	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
				       tvlv_len);
@@ -2705,8 +2720,10 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
 *
 * Fills the tvlv buff with the tt entries from the specified hash. If valid_cb
 * is not provided then this becomes a no-op.
 *
 * Return: Remaining unused length in tvlv_buff.
 */
static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
				   struct batadv_hashtable *hash,
				   void *tvlv_buff, u16 tt_len,
				   bool (*valid_cb)(const void *,
@@ -2726,7 +2743,7 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
	tt_change = tvlv_buff;

	if (!valid_cb)
		return;
		return tt_len;

	rcu_read_lock();
	for (i = 0; i < hash->size; i++) {
@@ -2752,6 +2769,8 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
		}
	}
	rcu_read_unlock();

	return batadv_tt_len(tt_tot - tt_num_entries);
}

/**
@@ -3022,7 +3041,8 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
			goto out;

		/* fill the rest of the tvlv with the real TT entries */
		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash,
		tvlv_len -= batadv_tt_tvlv_generate(bat_priv,
						    bat_priv->tt.global_hash,
						    tt_change, tt_len,
						    batadv_tt_global_valid,
						    req_dst_orig_node);
@@ -3149,9 +3169,11 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
			goto out;

		/* fill the rest of the tvlv with the real TT entries */
		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash,
		tvlv_len -= batadv_tt_tvlv_generate(bat_priv,
						    bat_priv->tt.local_hash,
						    tt_change, tt_len,
					batadv_tt_local_valid, NULL);
						    batadv_tt_local_valid,
						    NULL);
	}

	tvlv_tt_data->flags = BATADV_TT_RESPONSE;