* [PATCH net v2] ipv4: fib_trie: prevent speculative out-of-bounds child access
@ 2026-10-10 5:37 Daniël Trujillo via B4 Relay
2026-10-10 6:32 ` Eric Dumazet
2026-10-11 5:53 ` netdev-bot+sashiko
0 siblings, 2 replies; 3+ messages in thread
From: Daniël Trujillo via B4 Relay @ 2026-10-10 5:37 UTC (permalink / raw)
To: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: netdev, linux-kernel, stable, Daniël Trujillo, Alexander Duyck
From: Daniël Trujillo <datrujillo@nvidia.com>
fib_table_lookup() checks the child index against the bounds before
passing it to get_child_rcu().
The index is derived from the lookup key, which in turn is derived from
flp->daddr. A userspace process can therefore influence the index by
triggering lookups for chosen destination IPv4 addresses.
If this bounds check is mispredicted as in-bounds, an out-of-bounds index
can be transiently passed to get_child_rcu(). The value loaded beyond the
child array is then treated as a node pointer. A later transient
dereference of that pointer can cause a data-dependent cache footprint.
This was found during Spectre-v1 research. Leakage was demonstrated with
instrumentation that delays branch resolution with a CLFLUSH before the
mispredicted branch and makes the leaked location
deterministic for reproducible measurement. In that setup, a
userspace-controlled IPv4 lookup key was able to trigger a transient
out-of-bounds child access. The transient use of the loaded value as a
pointer caused a data-dependent cache footprint that was recoverable from
userspace using Prime+Probe. A real-world attacker would likely
need to delay branch resolution, which was not demonstrated end-to-end
without the added CLFLUSH.
Sanitize the index with array_index_nospec() before accessing the child
array. This removed the observed leakage in the described setup.
Apply the hardening before setting cindex in fib_table_lookup(), because
cindex can later be used by the backtrace path to load another child
pointer. fib_find_node() has the same pattern, with the checked index
derived from a user-provided key in fib_table_insert() and
fib_table_delete(). leaf_walk_rcu() has a similar checked cindex before
get_child_rcu(), and the traversed state can be influenced by userspace
actions. fib_find_node() runs under RTNL and
leaf_walk_rcu() is not on the packet lookup hot path, so harden those
analogous accesses in the same way.
Fixes: 9f9e636d4f89 ("fib_trie: Optimize fib_table_lookup to avoid wasting time on loops/variables")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Daniël Trujillo <datrujillo@nvidia.com>
---
Changes in v2:
- Move array_index_nospec() before cindex is set in
fib_table_lookup() so the backtrace path cannot use an out-of-bounds index
(Eric Dumazet).
- Apply the same hardening to fib_find_node() and leaf_walk_rcu()
(Eric Dumazet).
- Add discovery/testing details of the gadget to the changelog.
- Link to v1: https://patch.msgid.link/20261008-fib-trie-nospec-v1-1-fa18726d485e@nvidia.com
To: David Ahern <dsahern@kernel.org>
To: Ido Schimmel <idosch@nvidia.com>
To: "David S. Miller" <davem@davemloft.net>
To: Eric Dumazet <edumazet@kernel.org>
To: Jakub Kicinski <kuba@kernel.org>
To: Paolo Abeni <pabeni@redhat.com>
To: Simon Horman <horms@kernel.org>
To: Alexander Duyck <alexander.h.duyck@redhat.com>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
net/ipv4/fib_trie.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 248514dce0cd..bdffeff58c95 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -61,6 +61,7 @@
#include <linux/export.h>
#include <linux/vmalloc.h>
#include <linux/notifier.h>
+#include <linux/nospec.h>
#include <net/net_namespace.h>
#include <net/inet_dscp.h>
#include <net/ip.h>
@@ -961,6 +962,8 @@ static struct key_vector *fib_find_node(struct trie *t,
break;
}
+ index = array_index_nospec(index, 1ul << n->bits);
+
/* keep searching until we find a perfect match leaf or NULL */
} while (IS_TNODE(n));
@@ -1466,6 +1469,8 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
if (IS_LEAF(n))
goto found;
+ index = array_index_nospec(index, 1ul << n->bits);
+
/* only record pn and cindex if we are going to be chopping
* bits later. Otherwise we are just wasting cycles.
*/
@@ -1766,6 +1771,8 @@ static struct key_vector *leaf_walk_rcu(struct key_vector **tn, t_key key)
if (cindex >> pn->bits)
break;
+ cindex = array_index_nospec(cindex, 1ul << pn->bits);
+
/* descend into the next child */
n = get_child_rcu(pn, cindex++);
if (!n)
@@ -1787,6 +1794,8 @@ static struct key_vector *leaf_walk_rcu(struct key_vector **tn, t_key key)
continue;
}
+ cindex = array_index_nospec(cindex, 1ul << pn->bits);
+
/* grab the next available node */
n = get_child_rcu(pn, cindex++);
if (!n)
---
base-commit: af32da41b0327b9c6a37856ba82b6760d6c8d10e
change-id: 20261008-fib-trie-nospec-5c76028c8e7c
Best regards,
--
Daniël Trujillo <datrujillo@nvidia.com>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v2] ipv4: fib_trie: prevent speculative out-of-bounds child access
2026-10-10 5:37 [PATCH net v2] ipv4: fib_trie: prevent speculative out-of-bounds child access Daniël Trujillo via B4 Relay
@ 2026-10-10 6:32 ` Eric Dumazet
2026-10-11 5:53 ` netdev-bot+sashiko
1 sibling, 0 replies; 3+ messages in thread
From: Eric Dumazet @ 2026-10-10 6:32 UTC (permalink / raw)
To: datrujillo
Cc: David Ahern, Ido Schimmel, David S. Miller, Jakub Kicinski,
Paolo Abeni, Simon Horman, netdev, linux-kernel, stable,
Alexander Duyck
Le sam. 10 oct. 2026 à 07:37, Daniël Trujillo via B4 Relay
<devnull+datrujillo.nvidia.com@kernel.org> a écrit :
>
> From: Daniël Trujillo <datrujillo@nvidia.com>
>
> fib_table_lookup() checks the child index against the bounds before
> passing it to get_child_rcu().
>
> The index is derived from the lookup key, which in turn is derived from
> flp->daddr. A userspace process can therefore influence the index by
> triggering lookups for chosen destination IPv4 addresses.
>
> If this bounds check is mispredicted as in-bounds, an out-of-bounds index
> can be transiently passed to get_child_rcu(). The value loaded beyond the
> child array is then treated as a node pointer. A later transient
> dereference of that pointer can cause a data-dependent cache footprint.
>
> This was found during Spectre-v1 research. Leakage was demonstrated with
> instrumentation that delays branch resolution with a CLFLUSH before the
> mispredicted branch and makes the leaked location
> deterministic for reproducible measurement. In that setup, a
> userspace-controlled IPv4 lookup key was able to trigger a transient
> out-of-bounds child access. The transient use of the loaded value as a
> pointer caused a data-dependent cache footprint that was recoverable from
> userspace using Prime+Probe. A real-world attacker would likely
> need to delay branch resolution, which was not demonstrated end-to-end
> without the added CLFLUSH.
>
> Sanitize the index with array_index_nospec() before accessing the child
> array. This removed the observed leakage in the described setup.
>
> Apply the hardening before setting cindex in fib_table_lookup(), because
> cindex can later be used by the backtrace path to load another child
> pointer. fib_find_node() has the same pattern, with the checked index
> derived from a user-provided key in fib_table_insert() and
> fib_table_delete(). leaf_walk_rcu() has a similar checked cindex before
> get_child_rcu(), and the traversed state can be influenced by userspace
> actions. fib_find_node() runs under RTNL and
> leaf_walk_rcu() is not on the packet lookup hot path, so harden those
> analogous accesses in the same way.
>
> Fixes: 9f9e636d4f89 ("fib_trie: Optimize fib_table_lookup to avoid wasting time on loops/variables")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Daniël Trujillo <datrujillo@nvidia.com>
> ---
> Changes in v2:
> - Move array_index_nospec() before cindex is set in
> fib_table_lookup() so the backtrace path cannot use an out-of-bounds index
> (Eric Dumazet).
> - Apply the same hardening to fib_find_node() and leaf_walk_rcu()
> (Eric Dumazet).
> - Add discovery/testing details of the gadget to the changelog.
> - Link to v1: https://patch.msgid.link/20261008-fib-trie-nospec-v1-1-fa18726d485e@nvidia.com
>
This looks good to me, let's wait for final Sashiko findings.
Choice of net vs net-next tree is also debatable given that
performance impacts are unknown.
Thanks.
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v2] ipv4: fib_trie: prevent speculative out-of-bounds child access
2026-10-10 5:37 [PATCH net v2] ipv4: fib_trie: prevent speculative out-of-bounds child access Daniël Trujillo via B4 Relay
2026-10-10 6:32 ` Eric Dumazet
@ 2026-10-11 5:53 ` netdev-bot+sashiko
1 sibling, 0 replies; 3+ messages in thread
From: netdev-bot+sashiko @ 2026-10-11 5:53 UTC (permalink / raw)
To: datrujillo
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms, netdev,
linux-kernel, stable, alexander.h.duyck
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] The patch's Spectre-v1 hardening leaves out
fib_trie_get_next() in net/ipv4/fib_trie.c, which is the depth-first…
--
ipv4: fib_trie: prevent speculative out-of-bounds child access
This patch adds array_index_nospec() sanitization of the child index
before get_child_rcu() in fib_table_lookup(), fib_find_node() and both
loops of leaf_walk_rcu(). It closes a Spectre-v1 gadget where a
mispredicted bounds check lets an out-of-bounds tnode[] slot be
transiently used as a node pointer.
> diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
> index 248514dce0cdd..bdffeff58c950 100644
> --- a/net/ipv4/fib_trie.c
> +++ b/net/ipv4/fib_trie.c
[ ... ]
> @@ -1787,6 +1794,8 @@ static struct key_vector *leaf_walk_rcu(struct key_vector **tn, t_key key)
> continue;
> }
>
> + cindex = array_index_nospec(cindex, 1ul << pn->bits);
> +
> /* grab the next available node */
> n = get_child_rcu(pn, cindex++);
> if (!n)
[Severity: Medium]
The commit message says "leaf_walk_rcu() has a similar checked cindex
before get_child_rcu(), and the traversed state can be influenced by
userspace actions". Should fib_trie_get_next() get the same treatment?
It has the same shape as this sibling walk in leaf_walk_rcu(). The only
bound is the loop condition:
net/ipv4/fib_trie.c:fib_trie_get_next() {
...
while (!IS_TRIE(pn)) {
while (cindex < child_length(pn)) {
struct key_vector *n = get_child_rcu(pn, cindex++);
if (!n)
continue;
if (IS_LEAF(n)) {
...
/* Current node exhausted, pop back up */
pkey = pn->key;
pn = node_parent_rcu(pn);
cindex = get_index(pkey, pn) + 1;
...
}
Suppose the cindex < child_length(pn) check is mispredicted on the last
iteration. Could pn->tnode[child_length(pn)] then be loaded transiently
and dereferenced as a node pointer by IS_LEAF(n)? This hunk sanitizes
the same one-past-the-end case in leaf_walk_rcu().
fib_trie_get_next() is reachable from the 0444 /proc/net/fib_trie and
/proc/net/fib_triestat files, via fib_trie_seq_ops and
fib_triestat_seq_show()->trie_collect_stats(). Any local user can drive
it, and an unprivileged user and net namespace can shape the trie
contents.
Here the out-of-bounds index is always one past the end, so an attacker
can't choose it. That makes exploitation speculative. Would something
like this keep the hardening consistent?
while (cindex < child_length(pn)) {
struct key_vector *n;
cindex = array_index_nospec(cindex, child_length(pn));
n = get_child_rcu(pn, cindex++);
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261010-fib-trie-nospec-v2-1-30319b4db8d0%40nvidia.com
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-11 5:53 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-10 5:37 [PATCH net v2] ipv4: fib_trie: prevent speculative out-of-bounds child access Daniël Trujillo via B4 Relay
2026-10-10 6:32 ` Eric Dumazet
2026-10-11 5:53 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®