From: Simon Wunderlich <sw@simonwunderlich.de>
To: netdev@vger.kernel.org
Cc: "David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
b.a.t.m.a.n@lists.open-mesh.org,
Sven Eckelmann <sven@narfation.org>,
stable@kernel.org, Simon Wunderlich <sw@simonwunderlich.de>
Subject: [PATCH net 15/15] batman-adv: tvlv: avoid race of cifsnotfound handler state
Date: Fri, 19 Jun 2026 09:00:45 +0200 [thread overview]
Message-ID: <20260619070045.438101-16-sw@simonwunderlich.de> (raw)
In-Reply-To: <20260619070045.438101-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
TVLV handlers can have the flag BATADV_TVLV_HANDLER_OGM_CIFNOTFND set to
signal that the OGM handler should be called (with NULL for data) when the
specific TVLV container was not found in the OGM. This is used by:
* DAT
* GW
* Multicast (OGM + Tracker)
The state whether the handler was executed was stored in the struct
batadv_tvlv_handler. But the TVLV processing is started without any lock.
Multiple parallel contexts processing TVLVs would therefore overwrite each
others BATADV_TVLV_HANDLER_OGM_CALLED flag in the shared
batadv_tvlv_handler.
Drop the shared BATADV_TVLV_HANDLER_OGM_CALLED flag and instead determine,
per TVLV buffer, whether a matching container was present by scanning the
packet's buffer.
Cc: stable@kernel.org
Fixes: ef26157747d4 ("batman-adv: tvlv - basic infrastructure")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tvlv.c | 63 ++++++++++++++++++++++++++++++++++++++----
net/batman-adv/types.h | 7 -----
2 files changed, 57 insertions(+), 13 deletions(-)
diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c
index a957555d8958d..1c9fb21985f6a 100644
--- a/net/batman-adv/tvlv.c
+++ b/net/batman-adv/tvlv.c
@@ -411,7 +411,6 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
tvlv_handler->ogm_handler(bat_priv, orig_node,
BATADV_NO_FLAGS,
tvlv_value, tvlv_value_len);
- tvlv_handler->flags |= BATADV_TVLV_HANDLER_OGM_CALLED;
break;
case BATADV_UNICAST_TVLV:
if (!skb)
@@ -443,6 +442,48 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
return NET_RX_SUCCESS;
}
+/**
+ * batadv_tvlv_containers_contain() - check if a tvlv buffer holds a container
+ * @tvlv_value: tvlv content
+ * @tvlv_value_len: tvlv content length
+ * @type: tvlv container type to look for
+ * @version: tvlv container version to look for
+ *
+ * Return: true if a container of the given type and version is present in the
+ * tvlv buffer, false otherwise.
+ */
+static bool batadv_tvlv_containers_contain(void *tvlv_value,
+ u16 tvlv_value_len, u8 type,
+ u8 version)
+{
+ struct batadv_tvlv_hdr *tvlv_hdr;
+ u16 tvlv_value_cont_len;
+
+ while (tvlv_value_len >= sizeof(*tvlv_hdr)) {
+ tvlv_hdr = tvlv_value;
+ tvlv_value_cont_len = ntohs(tvlv_hdr->len);
+ tvlv_value = tvlv_hdr + 1;
+ tvlv_value_len -= sizeof(*tvlv_hdr);
+
+ if (tvlv_value_cont_len > tvlv_value_len)
+ break;
+
+ /* the next tvlv header is accessed assuming (at least) 2-byte
+ * alignment, so it must start at an even offset.
+ */
+ if (tvlv_value_cont_len & 1)
+ break;
+
+ if (tvlv_hdr->type == type && tvlv_hdr->version == version)
+ return true;
+
+ tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
+ tvlv_value_len -= tvlv_value_cont_len;
+ }
+
+ return false;
+}
+
/**
* batadv_tvlv_containers_process() - parse the given tvlv buffer to call the
* appropriate handlers
@@ -462,7 +503,9 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
struct sk_buff *skb, void *tvlv_value,
u16 tvlv_value_len)
{
+ u16 tvlv_value_start_len = tvlv_value_len;
struct batadv_tvlv_handler *tvlv_handler;
+ void *tvlv_value_start = tvlv_value;
struct batadv_tvlv_hdr *tvlv_hdr;
u16 tvlv_value_cont_len;
u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND;
@@ -506,12 +549,20 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
if (!tvlv_handler->ogm_handler)
continue;
- if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) &&
- !(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CALLED))
- tvlv_handler->ogm_handler(bat_priv, orig_node,
- cifnotfound, NULL, 0);
+ if (!(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND))
+ continue;
- tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED;
+ /* if the corresponding container was present then the handler
+ * was already called from the loop above
+ */
+ if (batadv_tvlv_containers_contain(tvlv_value_start,
+ tvlv_value_start_len,
+ tvlv_handler->type,
+ tvlv_handler->version))
+ continue;
+
+ tvlv_handler->ogm_handler(bat_priv, orig_node,
+ cifnotfound, NULL, 0);
}
rcu_read_unlock();
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 3de3c1ac0244f..b1f9f8964c3fd 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -2294,13 +2294,6 @@ enum batadv_tvlv_handler_flags {
* will call this handler even if its type was not found (with no data)
*/
BATADV_TVLV_HANDLER_OGM_CIFNOTFND = BIT(1),
-
- /**
- * @BATADV_TVLV_HANDLER_OGM_CALLED: interval tvlv handling flag - the
- * API marks a handler as being called, so it won't be called if the
- * BATADV_TVLV_HANDLER_OGM_CIFNOTFND flag was set
- */
- BATADV_TVLV_HANDLER_OGM_CALLED = BIT(2),
};
#endif /* _NET_BATMAN_ADV_TYPES_H_ */
--
2.47.3
prev parent reply other threads:[~2026-06-19 7:00 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-19 7:00 [PATCH net 00/15] pull request: batman-adv 2026-06-19 Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 01/15] batman-adv: gw: don't deselect gateway with active hardif Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 02/15] batman-adv: ensure bcast is writable before modifying TTL Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 03/15] batman-adv: fix (m|b)cast csum after decrementing TTL Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 04/15] batman-adv: frag: ensure fragment is writable before modifying TTL Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 05/15] batman-adv: frag: avoid underflow of TTL Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 06/15] batman-adv: v: prevent OGM aggregation on disabled hardif Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 07/15] batman-adv: tp_meter: restrict number of unacked list entries Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 08/15] batman-adv: tp_meter: annotate last_recv_time access with READ/WRITE_ONCE Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 09/15] batman-adv: tp_meter: prevent parallel modifications of last_recv Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 10/15] batman-adv: tp_meter: handle overlapping packets Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 11/15] batman-adv: tt: don't merge change entries with different VIDs Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 12/15] batman-adv: tt: track roam count per VID Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 13/15] batman-adv: dat: prevent false sharing between VLANs Simon Wunderlich
2026-06-19 7:00 ` [PATCH net 14/15] batman-adv: tvlv: enforce 2-byte alignment Simon Wunderlich
2026-06-19 7:00 ` Simon Wunderlich [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260619070045.438101-16-sw@simonwunderlich.de \
--to=sw@simonwunderlich.de \
--cc=b.a.t.m.a.n@lists.open-mesh.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@kernel.org \
--cc=sven@narfation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox