net: synchronize proc_do_rss_key() with netdev_rss_key_fill()

proc_do_rss_key() reads netdev_rss_key[] without synchronization, so a
concurrent reader of /proc/sys/net/core/netdev_rss_key can observe a
partially populated key while netdev_rss_key_fill() is initializing it.

Publish a boolean flag after an smp_wmb() once netdev_rss_key_fill() has
populated netdev_rss_key[], and pair it with an smp_rmb() in
proc_do_rss_key(), printing zero bytes until the flag is set.

Fixes: 960fb622f8 ("net: provide a per host RSS key generic infrastructure")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260922163458.3900996-2-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet 2026-09-22 16:34:55 +00:00 committed by Jakub Kicinski
parent 42a9fb3382
commit 9396e37c48
3 changed files with 14 additions and 1 deletions

View File

@ -95,6 +95,7 @@ extern int netdev_unregister_timeout_secs;
extern int weight_p;
extern int dev_weight_rx_bias;
extern int dev_weight_tx_bias;
extern bool netdev_rss_key_initialized;
extern struct rw_semaphore dev_addr_sem;

View File

@ -337,10 +337,15 @@ static int proc_do_rss_key(const struct ctl_table *table, int write,
{
char buf[NETDEV_RSS_KEY_LEN * 3];
struct ctl_table fake_table;
bool initialized;
char *pos = buf;
initialized = READ_ONCE(netdev_rss_key_initialized);
/* Pair with smp_wmb() in netdev_rss_key_fill(). */
smp_rmb();
for (int i = 0; i < NETDEV_RSS_KEY_LEN; i++) {
pos = hex_byte_pack(pos, netdev_rss_key[i]);
pos = hex_byte_pack(pos, initialized ? netdev_rss_key[i] : 0);
*pos++ = ':';
}
*(--pos) = 0;

View File

@ -34,6 +34,7 @@
#include <net/netdev_lock.h>
#include <net/netdev_queues.h>
#include "../core/dev.h"
#include "common.h"
/* State held across locks and calls for commands which have devlink fallback */
@ -1302,11 +1303,17 @@ static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
}
u8 netdev_rss_key[NETDEV_RSS_KEY_LEN] __read_mostly;
bool netdev_rss_key_initialized __read_mostly;
void netdev_rss_key_fill(void *buffer, size_t len)
{
BUG_ON(len > sizeof(netdev_rss_key));
net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key));
if (unlikely(!READ_ONCE(netdev_rss_key_initialized))) {
/* Pair with smp_rmb() in proc_do_rss_key(). */
smp_wmb();
WRITE_ONCE(netdev_rss_key_initialized, true);
}
memcpy(buffer, netdev_rss_key, len);
}
EXPORT_SYMBOL(netdev_rss_key_fill);