In blk_register_tracepoints(), register_trace_*() functions are called with
WARN_ON(ret). Tracepoint registration allocates memory for probe arrays and
can legitimately fail with -ENOMEM under memory pressure. WARN_ON() must
not be used for conditions that can legitimately happen.
WARNING: kernel/trace/blktrace.c:1332 at blk_register_tracepoints
kernel/trace/blktrace.c:1332 [inline]
WARNING: kernel/trace/blktrace.c:1332 at get_probe_ref+0x377/0x470
kernel/trace/blktrace.c:492
RIP: 0010:blk_register_tracepoints kernel/trace/blktrace.c:1332 [inline]
RIP: 0010:get_probe_ref+0x377/0x470 kernel/trace/blktrace.c:492
Call Trace:
blk_trace_setup_queue kernel/trace/blktrace.c:1920 [inline]
sysfs_blk_trace_attr_store+0xb1d/0x11e0 kernel/trace/blktrace.c:2116
kernfs_fop_write_iter+0x3a4/0x540 fs/kernfs/file.c:345
vfs_write+0x612/0xba0 fs/read_write.c:687
ksys_write+0x150/0x270 fs/read_write.c:739
do_syscall_64+0x155/0x510 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Furthermore, blk_register_tracepoints() ignores registration errors and
continues, leaving tracepoints in a partially registered state. When
blktrace is later stopped, blk_unregister_tracepoints() unconditionally
attempts to unregister all tracepoints, which fails with -ENOENT and
triggers an additional warning in tracepoint_remove_func().
Fix this by removing WARN_ON() and properly handling registration failures
in blk_register_tracepoints(). If any registration fails, unwinding is
performed by unregistering previously registered tracepoints in reverse
order, synchronizing tracepoint unregistration, and returning the error
code. In addition, propagate the error through get_probe_ref(),
blk_trace_setup_finalize(), and the setup entry points (blk_trace_setup(),
blk_trace_setup2(), compat_blk_trace_setup(), and blk_trace_setup_queue()),
properly cleaning up allocated resources on failure.
Fixes: 5f3ea37c7716 ("blktrace: port to tracepoints")
Assisted-by: Gemini:gemini-3.7-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: syzbot+c54ded83396afee31eb1@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c54ded83396afee31eb1
Link: https://syzkaller.appspot.com/ai_job?id=b81a3c49-0fe5-44e7-bf10-a4e460a67fe2
To: "Jens Axboe"
To:
To:
To: "Masami Hiramatsu"
To: "Steven Rostedt"
To: "Arnaldo Carvalho de Melo"
Cc:
Cc: "Mathieu Desnoyers"
---
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 8cd2520b4..c2324298c 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -60,7 +60,7 @@ static struct tracer_flags blk_tracer_flags = {
static DEFINE_MUTEX(blk_probe_mutex);
static int blk_probes_ref;
-static void blk_register_tracepoints(void);
+static int blk_register_tracepoints(void);
static void blk_unregister_tracepoints(void);
static void record_blktrace_event(struct blk_io_trace *t, pid_t pid, int cpu,
@@ -485,12 +485,18 @@ static void blk_trace_free(struct request_queue *q, struct blk_trace *bt)
kfree(bt);
}
-static void get_probe_ref(void)
+static int get_probe_ref(void)
{
+ int ret = 0;
+
mutex_lock(&blk_probe_mutex);
- if (++blk_probes_ref == 1)
- blk_register_tracepoints();
+ if (++blk_probes_ref == 1) {
+ ret = blk_register_tracepoints();
+ if (ret)
+ blk_probes_ref--;
+ }
mutex_unlock(&blk_probe_mutex);
+ return ret;
}
static void put_probe_ref(void)
@@ -727,12 +733,14 @@ static struct blk_trace *blk_trace_setup_prepare(struct request_queue *q,
return ERR_PTR(ret);
}
-static void blk_trace_setup_finalize(struct request_queue *q,
- char *name, int version,
- struct blk_trace *bt,
- struct blk_user_trace_setup2 *buts)
+static int blk_trace_setup_finalize(struct request_queue *q,
+ char *name, int version,
+ struct blk_trace *bt,
+ struct blk_user_trace_setup2 *buts)
{
+ int ret;
+
strscpy_pad(buts->name, name, BLKTRACE_BDEV_SIZE2);
/*
@@ -755,8 +763,12 @@ static void blk_trace_setup_finalize(struct request_queue *q,
bt->pid = buts->pid;
bt->trace_state = Blktrace_setup;
+ ret = get_probe_ref();
+ if (ret)
+ return ret;
+
rcu_assign_pointer(q->blk_trace, bt);
- get_probe_ref();
+ return 0;
}
int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
@@ -792,7 +804,12 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
blk_debugfs_unlock(q, memflags);
return PTR_ERR(bt);
}
- blk_trace_setup_finalize(q, name, 1, bt, &buts2);
+ ret = blk_trace_setup_finalize(q, name, 1, bt, &buts2);
+ if (ret) {
+ blk_trace_free(q, bt);
+ blk_debugfs_unlock(q, memflags);
+ return ret;
+ }
strscpy(buts.name, buts2.name, BLKTRACE_BDEV_SIZE);
blk_debugfs_unlock(q, memflags);
@@ -810,6 +827,7 @@ static int blk_trace_setup2(struct request_queue *q, char *name, dev_t dev,
struct blk_user_trace_setup2 buts2;
struct blk_trace *bt;
unsigned int memflags;
+ int ret;
if (copy_from_user(&buts2, arg, sizeof(buts2)))
return -EFAULT;
@@ -827,7 +845,12 @@ static int blk_trace_setup2(struct request_queue *q, char *name, dev_t dev,
blk_debugfs_unlock(q, memflags);
return PTR_ERR(bt);
}
- blk_trace_setup_finalize(q, name, 2, bt, &buts2);
+ ret = blk_trace_setup_finalize(q, name, 2, bt, &buts2);
+ if (ret) {
+ blk_trace_free(q, bt);
+ blk_debugfs_unlock(q, memflags);
+ return ret;
+ }
blk_debugfs_unlock(q, memflags);
if (copy_to_user(arg, &buts2, sizeof(buts2))) {
@@ -846,6 +869,7 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
struct compat_blk_user_trace_setup cbuts;
struct blk_trace *bt;
unsigned int memflags;
+ int ret;
if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
return -EFAULT;
@@ -869,7 +893,12 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
blk_debugfs_unlock(q, memflags);
return PTR_ERR(bt);
}
- blk_trace_setup_finalize(q, name, 1, bt, &buts2);
+ ret = blk_trace_setup_finalize(q, name, 1, bt, &buts2);
+ if (ret) {
+ blk_trace_free(q, bt);
+ blk_debugfs_unlock(q, memflags);
+ return ret;
+ }
blk_debugfs_unlock(q, memflags);
if (copy_to_user(arg, &buts2.name, ARRAY_SIZE(buts2.name))) {
@@ -1324,49 +1353,108 @@ void blk_add_driver_data(struct request *rq, void *data, size_t len)
}
EXPORT_SYMBOL_GPL(blk_add_driver_data);
-static void blk_register_tracepoints(void)
+static int blk_register_tracepoints(void)
{
int ret;
ret = register_trace_block_rq_insert(blk_add_trace_rq_insert, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out;
ret = register_trace_block_rq_issue(blk_add_trace_rq_issue, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_rq_insert;
ret = register_trace_block_rq_merge(blk_add_trace_rq_merge, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_rq_issue;
ret = register_trace_block_rq_requeue(blk_add_trace_rq_requeue, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_rq_merge;
ret = register_trace_block_rq_complete(blk_add_trace_rq_complete, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_rq_requeue;
ret = register_trace_block_bio_complete(blk_add_trace_bio_complete, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_rq_complete;
ret = register_trace_block_bio_backmerge(blk_add_trace_bio_backmerge, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_bio_complete;
ret = register_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_bio_backmerge;
ret = register_trace_block_bio_queue(blk_add_trace_bio_queue, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_bio_frontmerge;
ret = register_trace_block_getrq(blk_add_trace_getrq, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_bio_queue;
ret = register_trace_blk_zone_append_update_request_bio(
blk_add_trace_zone_update_request, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_getrq;
ret = register_trace_disk_zone_wplug_add_bio(blk_add_trace_zone_plug,
NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_zone_update_request;
ret = register_trace_blk_zone_wplug_bio(blk_add_trace_zone_unplug,
NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_zone_plug;
ret = register_trace_block_plug(blk_add_trace_plug, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_zone_unplug;
ret = register_trace_block_unplug(blk_add_trace_unplug, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_plug;
ret = register_trace_block_split(blk_add_trace_split, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_unplug;
ret = register_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_split;
ret = register_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);
- WARN_ON(ret);
+ if (ret)
+ goto out_bio_remap;
+
+ return 0;
+
+out_bio_remap:
+ unregister_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);
+out_split:
+ unregister_trace_block_split(blk_add_trace_split, NULL);
+out_unplug:
+ unregister_trace_block_unplug(blk_add_trace_unplug, NULL);
+out_plug:
+ unregister_trace_block_plug(blk_add_trace_plug, NULL);
+out_zone_unplug:
+ unregister_trace_blk_zone_wplug_bio(blk_add_trace_zone_unplug, NULL);
+out_zone_plug:
+ unregister_trace_disk_zone_wplug_add_bio(blk_add_trace_zone_plug, NULL);
+out_zone_update_request:
+ unregister_trace_blk_zone_append_update_request_bio(
+ blk_add_trace_zone_update_request, NULL);
+out_getrq:
+ unregister_trace_block_getrq(blk_add_trace_getrq, NULL);
+out_bio_queue:
+ unregister_trace_block_bio_queue(blk_add_trace_bio_queue, NULL);
+out_bio_frontmerge:
+ unregister_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge, NULL);
+out_bio_backmerge:
+ unregister_trace_block_bio_backmerge(blk_add_trace_bio_backmerge, NULL);
+out_bio_complete:
+ unregister_trace_block_bio_complete(blk_add_trace_bio_complete, NULL);
+out_rq_complete:
+ unregister_trace_block_rq_complete(blk_add_trace_rq_complete, NULL);
+out_rq_requeue:
+ unregister_trace_block_rq_requeue(blk_add_trace_rq_requeue, NULL);
+out_rq_merge:
+ unregister_trace_block_rq_merge(blk_add_trace_rq_merge, NULL);
+out_rq_issue:
+ unregister_trace_block_rq_issue(blk_add_trace_rq_issue, NULL);
+out_rq_insert:
+ unregister_trace_block_rq_insert(blk_add_trace_rq_insert, NULL);
+ tracepoint_synchronize_unregister();
+out:
+ return ret;
}
static void blk_unregister_tracepoints(void)
@@ -1916,8 +2004,11 @@ static int blk_trace_setup_queue(struct request_queue *q,
blk_trace_setup_lba(bt, bdev);
+ ret = get_probe_ref();
+ if (ret)
+ goto free_bt;
+
rcu_assign_pointer(q->blk_trace, bt);
- get_probe_ref();
return 0;
free_bt:
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).
See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at syzkaller@googlegroups.com.