mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-07-14 21:43:02 +02:00
[ Upstream commit605b52497b] rlb_clear_slave intentionally keeps RLB hash-table entries on the rx_hashtbl_used_head list with slave set to NULL when no replacement slave is available. However, bond_debug_rlb_hash_show visites client_info->slave without checking if it's NULL. Other used-list iterators in bond_alb.c already handle this NULL-slave state safely: - rlb_update_client returns early on !client_info->slave - rlb_req_update_slave_clients, rlb_clear_slave, and rlb_rebalance compare slave values before visiting - lb_req_update_subnet_clients continues if slave is NULL The following NULL deref crash can be trigger in bond_debug_rlb_hash_show: [ 1.289791] BUG: kernel NULL pointer dereference, address: 0000000000000000 [ 1.292058] RIP: 0010:bond_debug_rlb_hash_show (drivers/net/bonding/bond_debugfs.c:41) [ 1.293101] RSP: 0018:ffffc900004a7d00 EFLAGS: 00010286 [ 1.293333] RAX: 0000000000000000 RBX: ffff888102b48200 RCX: ffff888102b48204 [ 1.293631] RDX: ffff888102b48200 RSI: ffffffff839daad5 RDI: ffff888102815078 [ 1.293924] RBP: ffff888102815078 R08: ffff888102b4820e R09: 0000000000000000 [ 1.294267] R10: 0000000000000000 R11: 0000000000000000 R12: ffff888100f929c0 [ 1.294564] R13: ffff888100f92a00 R14: 0000000000000001 R15: ffffc900004a7ed8 [ 1.294864] FS: 0000000001395380(0000) GS:ffff888196e75000(0000) knlGS:0000000000000000 [ 1.295239] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1.295480] CR2: 0000000000000000 CR3: 0000000102adc004 CR4: 0000000000772ef0 [ 1.295897] Call Trace: [ 1.296134] seq_read_iter (fs/seq_file.c:231) [ 1.296341] seq_read (fs/seq_file.c:164) [ 1.296493] full_proxy_read (fs/debugfs/file.c:378 (discriminator 1)) [ 1.296658] vfs_read (fs/read_write.c:572) [ 1.296981] ksys_read (fs/read_write.c:717) [ 1.297132] do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) [ 1.297325] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) Add a NULL check and print "(none)" for entries with no assigned slave. Fixes:caafa84251("bonding: add the debugfs interface to see RLB hash table") Reported-by: Weiming Shi <bestswngs@gmail.com> Signed-off-by: Xiang Mei <xmei5@asu.edu> Link: https://patch.msgid.link/20260317005034.1888794-1-xmei5@asu.edu Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
122 lines
2.6 KiB
C
122 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <net/bonding.h>
|
|
#include <net/bond_alb.h>
|
|
|
|
#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_NET_NS)
|
|
|
|
#include <linux/debugfs.h>
|
|
#include <linux/seq_file.h>
|
|
|
|
static struct dentry *bonding_debug_root;
|
|
|
|
/* Show RLB hash table */
|
|
static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
|
|
{
|
|
struct bonding *bond = m->private;
|
|
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
|
|
struct rlb_client_info *client_info;
|
|
u32 hash_index;
|
|
|
|
if (BOND_MODE(bond) != BOND_MODE_ALB)
|
|
return 0;
|
|
|
|
seq_printf(m, "SourceIP DestinationIP "
|
|
"Destination MAC DEV\n");
|
|
|
|
spin_lock_bh(&bond->mode_lock);
|
|
|
|
hash_index = bond_info->rx_hashtbl_used_head;
|
|
for (; hash_index != RLB_NULL_INDEX;
|
|
hash_index = client_info->used_next) {
|
|
client_info = &(bond_info->rx_hashtbl[hash_index]);
|
|
if (client_info->slave)
|
|
seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
|
|
&client_info->ip_src,
|
|
&client_info->ip_dst,
|
|
&client_info->mac_dst,
|
|
client_info->slave->dev->name);
|
|
else
|
|
seq_printf(m, "%-15pI4 %-15pI4 %-17pM (none)\n",
|
|
&client_info->ip_src,
|
|
&client_info->ip_dst,
|
|
&client_info->mac_dst);
|
|
}
|
|
|
|
spin_unlock_bh(&bond->mode_lock);
|
|
|
|
return 0;
|
|
}
|
|
DEFINE_SHOW_ATTRIBUTE(bond_debug_rlb_hash);
|
|
|
|
void bond_debug_register(struct bonding *bond)
|
|
{
|
|
bond->debug_dir =
|
|
debugfs_create_dir(bond->dev->name, bonding_debug_root);
|
|
|
|
debugfs_create_file("rlb_hash_table", 0400, bond->debug_dir,
|
|
bond, &bond_debug_rlb_hash_fops);
|
|
}
|
|
|
|
void bond_debug_unregister(struct bonding *bond)
|
|
{
|
|
debugfs_remove_recursive(bond->debug_dir);
|
|
}
|
|
|
|
void bond_debug_reregister(struct bonding *bond)
|
|
{
|
|
struct dentry *d;
|
|
|
|
d = debugfs_rename(bonding_debug_root, bond->debug_dir,
|
|
bonding_debug_root, bond->dev->name);
|
|
if (!IS_ERR(d)) {
|
|
bond->debug_dir = d;
|
|
} else {
|
|
netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n");
|
|
bond_debug_unregister(bond);
|
|
}
|
|
}
|
|
|
|
void __init bond_create_debugfs(void)
|
|
{
|
|
bonding_debug_root = debugfs_create_dir("bonding", NULL);
|
|
|
|
if (IS_ERR(bonding_debug_root))
|
|
pr_warn("Warning: Cannot create bonding directory in debugfs\n");
|
|
}
|
|
|
|
void bond_destroy_debugfs(void)
|
|
{
|
|
debugfs_remove_recursive(bonding_debug_root);
|
|
bonding_debug_root = NULL;
|
|
}
|
|
|
|
|
|
#else /* !CONFIG_DEBUG_FS */
|
|
|
|
void bond_debug_register(struct bonding *bond)
|
|
{
|
|
}
|
|
|
|
void bond_debug_unregister(struct bonding *bond)
|
|
{
|
|
}
|
|
|
|
void bond_debug_reregister(struct bonding *bond)
|
|
{
|
|
}
|
|
|
|
void __init bond_create_debugfs(void)
|
|
{
|
|
}
|
|
|
|
void bond_destroy_debugfs(void)
|
|
{
|
|
}
|
|
|
|
#endif /* CONFIG_DEBUG_FS */
|