aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-09-15 17:58:36 -0700
committerJakub Kicinski <kuba@kernel.org>2026-09-15 17:58:37 -0700
commitad77dba64dc1a522014b2cd7376a67004140375b (patch)
treee1fd5a411c7bb76507456946395b90d730ebf81e
parentnet: ip_tunnel: initialize `options_len` before referencing options (diff)
parentdrop_monitor: fix out-of-bounds write in reset_per_cpu_data() (diff)
Merge branch 'net-drop_monitor-fix-concurrency-issues-preemption-warning-and-buffer-overrun'
Eric Dumazet says: ==================== net: drop_monitor: fix concurrency issues, preemption warning, and buffer overrun This series addresses several issues discovered in the drop_monitor subsystem: Patch 1 adds missing tracepoint unregistration synchronization to the net_dm_trace_on_set() error unwind path, preventing in-flight probes from scheduling work after the module reference has been dropped. Patch 2 resolves a race condition during monitoring teardown where per-CPU timers can be re-armed after deletion if a concurrent worker encounters a memory allocation failure, switching to timer_shutdown_sync(). Patch 3 fixes a CONFIG_DEBUG_PREEMPT warning reported by syzbot when kfree_skb() is invoked from preemptible process context, using raw_cpu_ptr() since each per-CPU queue is safely protected by its own spinlock. Patch 4 fixes an out-of-bounds write in reset_per_cpu_data() where memset() overwrote the allocated SKB tailroom by sizeof(struct nlattr) bytes. ==================== Link: https://patch.msgid.link/20260910204612.3762015-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--net/core/drop_monitor.c18
1 files changed, 9 insertions, 9 deletions
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index abaf108ac4db..edc660778408 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -141,9 +141,8 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)
al = sizeof(struct net_dm_alert_msg);
al += dm_hit_limit * sizeof(struct net_dm_drop_point);
- al += sizeof(struct nlattr);
- skb = genlmsg_new(al, GFP_KERNEL);
+ skb = genlmsg_new(nla_total_size(al), GFP_KERNEL);
if (!skb)
goto err;
@@ -448,7 +447,7 @@ net_dm_hw_trap_summary_probe(void *ignore, const struct devlink *devlink,
if (metadata->trap_type == DEVLINK_TRAP_TYPE_CONTROL)
return;
- hw_data = this_cpu_ptr(&dm_hw_cpu_data);
+ hw_data = raw_cpu_ptr(&dm_hw_cpu_data);
raw_spin_lock_irqsave(&hw_data->lock, flags);
hw_entries = hw_data->hw_entries;
@@ -516,7 +515,7 @@ static void net_dm_packet_trace_kfree_skb_hit(void *ignore,
*/
nskb->tstamp = tstamp;
- data = this_cpu_ptr(&dm_cpu_data);
+ data = raw_cpu_ptr(&dm_cpu_data);
spin_lock_irqsave(&data->drop_queue.lock, flags);
if (skb_queue_len(&data->drop_queue) < net_dm_queue_len)
@@ -983,7 +982,7 @@ net_dm_hw_trap_packet_probe(void *ignore, const struct devlink *devlink,
NET_DM_SKB_CB(nskb)->hw_metadata = n_hw_metadata;
nskb->tstamp = tstamp;
- hw_data = this_cpu_ptr(&dm_hw_cpu_data);
+ hw_data = raw_cpu_ptr(&dm_hw_cpu_data);
spin_lock_irqsave(&hw_data->drop_queue.lock, flags);
if (skb_queue_len(&hw_data->drop_queue) < net_dm_queue_len)
@@ -1083,7 +1082,7 @@ err_module_put:
struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu);
struct sk_buff *skb;
- timer_delete_sync(&hw_data->send_timer);
+ timer_shutdown_sync(&hw_data->send_timer);
cancel_work_sync(&hw_data->dm_alert_work);
while ((skb = __skb_dequeue(&hw_data->drop_queue))) {
struct devlink_trap_metadata *hw_metadata;
@@ -1117,7 +1116,7 @@ static void net_dm_hw_monitor_stop(struct netlink_ext_ack *extack)
struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu);
struct sk_buff *skb;
- timer_delete_sync(&hw_data->send_timer);
+ timer_shutdown_sync(&hw_data->send_timer);
cancel_work_sync(&hw_data->dm_alert_work);
while ((skb = __skb_dequeue(&hw_data->drop_queue))) {
struct devlink_trap_metadata *hw_metadata;
@@ -1173,12 +1172,13 @@ static int net_dm_trace_on_set(struct netlink_ext_ack *extack)
err_unregister_trace:
unregister_trace_kfree_skb(ops->kfree_skb_probe, NULL);
+ tracepoint_synchronize_unregister();
err_module_put:
for_each_possible_cpu(cpu) {
struct per_cpu_dm_data *data = &per_cpu(dm_cpu_data, cpu);
struct sk_buff *skb;
- timer_delete_sync(&data->send_timer);
+ timer_shutdown_sync(&data->send_timer);
cancel_work_sync(&data->dm_alert_work);
while ((skb = __skb_dequeue(&data->drop_queue)))
consume_skb(skb);
@@ -1206,7 +1206,7 @@ static void net_dm_trace_off_set(void)
struct per_cpu_dm_data *data = &per_cpu(dm_cpu_data, cpu);
struct sk_buff *skb;
- timer_delete_sync(&data->send_timer);
+ timer_shutdown_sync(&data->send_timer);
cancel_work_sync(&data->dm_alert_work);
while ((skb = __skb_dequeue(&data->drop_queue)))
consume_skb(skb);