| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/11 03:00 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The changes are strictly limited to user-space utilities (bpftool under tools/bpf/bpftool/) and selftests (tools/testing/selftests/bpf/). No kernel-space code or compiled kernel image (vmlinux/modules) is modified.",
"WorthFuzzing": false
} |
| 1/1 | 2026/09/11 03:00 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit d3ae3d9e355eb860db6da7ef33e14759f6b658c7\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Fri Sep 11 03:00:01 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst\nindex 5daf3de5c7446..e4ed7e701c9e4 100644\n--- a/tools/bpf/bpftool/Documentation/bpftool-map.rst\n+++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst\n@@ -120,7 +120,8 @@ bpftool map pin *MAP* *FILE*\n character ('.'), which is reserved for future extensions of *bpffs*.\n \n bpftool map event_pipe *MAP* [cpu *N* index *M*]\n- Read events from a **BPF_MAP_TYPE_PERF_EVENT_ARRAY** map.\n+ Read events from a **BPF_MAP_TYPE_PERF_EVENT_ARRAY** or\n+ **BPF_MAP_TYPE_RINGBUF** map.\n \n Install perf rings into a perf event array map and dump output of any\n **bpf_perf_event_output**\\ () call in the kernel. By default read the\n@@ -134,6 +135,17 @@ bpftool map event_pipe *MAP* [cpu *N* index *M*]\n existing ring. Any other application will stop receiving events if it\n installed its rings earlier.\n \n+ For a ring buffer map, consume records submitted by BPF programs, including\n+ records already queued before the command starts. **cpu** and **index**\n+ are not supported. Each record is printed in full, including embedded zero\n+ bytes. Plain output reports the record size followed by hexadecimal\n+ bytes; JSON output contains **size** and **data** fields, with **data** an\n+ array of byte values. Ring buffer records have no implicit CPU or timestamp.\n+\n+ Consuming a ring buffer advances its shared consumer position, so this\n+ command must not run alongside another consumer of the same map.\n+ **BPF_MAP_TYPE_USER_RINGBUF** maps are not supported.\n+\n bpftool map peek *MAP*\n Peek next value in the queue or stack.\n \ndiff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool\nindex 75cbcb512ebae..1750b488c9e3b 100644\n--- a/tools/bpf/bpftool/bash-completion/bpftool\n+++ b/tools/bpf/bpftool/bash-completion/bpftool\n@@ -878,11 +878,11 @@ _bpftool()\n return 0\n ;;\n id)\n- _bpftool_get_map_ids_for_type perf_event_array\n+ _bpftool_get_map_ids_for_type '\"type\": \"\\(perf_event_array\\|ringbuf\\)\"'\n return 0\n ;;\n name)\n- _bpftool_get_map_names_for_type perf_event_array\n+ _bpftool_get_map_names_for_type '\"type\": \"\\(perf_event_array\\|ringbuf\\)\"'\n return 0\n ;;\n cpu)\ndiff --git a/tools/bpf/bpftool/map_perf_ring.c b/tools/bpf/bpftool/map_perf_ring.c\nindex bcb767e2d6733..7d555331f443a 100644\n--- a/tools/bpf/bpftool/map_perf_ring.c\n+++ b/tools/bpf/bpftool/map_perf_ring.c\n@@ -27,7 +27,7 @@\n \n #define MMAP_PAGE_CNT\t16\n \n-static volatile bool stop;\n+static volatile sig_atomic_t stop;\n \n struct perf_event_sample {\n \tstruct perf_event_header header;\n@@ -44,7 +44,6 @@ struct perf_event_lost {\n \n static void int_exit(int signo)\n {\n-\tfprintf(stderr, \"Stopping...\\n\");\n \tstop = true;\n }\n \n@@ -107,6 +106,27 @@ print_bpf_output(void *private_data, int cpu, struct perf_event_header *event)\n \treturn LIBBPF_PERF_EVENT_CONT;\n }\n \n+static int print_ringbuf_output(void *ctx, void *data, size_t size)\n+{\n+\tif (json_output) {\n+\t\tjsonw_start_object(json_wtr);\n+\t\tjsonw_uint_field(json_wtr, \"size\", size);\n+\t\tjsonw_name(json_wtr, \"data\");\n+\t\tprint_data_json(data, size);\n+\t\tjsonw_end_object(json_wtr);\n+\t} else {\n+\t\tprintf(\"== size: %zu =====\\n\", size);\n+\t\tfprint_hex(stdout, data, size, \" \");\n+\t\tprintf(\"\\n\");\n+\t}\n+\n+\tif (fflush(stdout))\n+\t\treturn errno ? -errno : -EIO;\n+\n+\t/* A producer can keep poll() busy even after a signal arrives. */\n+\treturn stop ? -EINTR : 0;\n+}\n+\n int do_event_pipe(int argc, char **argv)\n {\n \tstruct perf_event_attr perf_attr = {\n@@ -123,18 +143,26 @@ int do_event_pipe(int argc, char **argv)\n \t\t.cpu = -1,\n \t\t.idx = -1,\n \t};\n-\tstruct perf_buffer *pb;\n+\tstruct perf_buffer *pb = NULL;\n+\tstruct ring_buffer *rb = NULL;\n \t__u32 map_info_len;\n \tint err, map_fd;\n \n+\tstop = false;\n \tmap_info_len = sizeof(map_info);\n \tmap_fd = map_parse_fd_and_info(\u0026argc, \u0026argv, \u0026map_info, \u0026map_info_len,\n \t\t\t\t 0);\n \tif (map_fd \u003c 0)\n \t\treturn -1;\n \n-\tif (map_info.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {\n-\t\tp_err(\"map is not a perf event array\");\n+\tif (map_info.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY \u0026\u0026\n+\t map_info.type != BPF_MAP_TYPE_RINGBUF) {\n+\t\tp_err(\"map is not a perf event array or ring buffer\");\n+\t\tgoto err_close_map;\n+\t}\n+\n+\tif (map_info.type == BPF_MAP_TYPE_RINGBUF \u0026\u0026 argc) {\n+\t\tp_err(\"ring buffer maps do not support cpu or index arguments\");\n \t\tgoto err_close_map;\n \t}\n \n@@ -184,15 +212,24 @@ int do_event_pipe(int argc, char **argv)\n \t\tctx.idx = 0;\n \t}\n \n-\topts.cpu_cnt = ctx.all_cpus ? 0 : 1;\n-\topts.cpus = \u0026ctx.cpu;\n-\topts.map_keys = \u0026ctx.idx;\n-\tpb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, \u0026perf_attr,\n-\t\t\t\t print_bpf_output, \u0026ctx, \u0026opts);\n-\tif (!pb) {\n-\t\tp_err(\"failed to create perf buffer: %s (%d)\",\n-\t\t strerror(errno), errno);\n-\t\tgoto err_close_map;\n+\tif (map_info.type == BPF_MAP_TYPE_RINGBUF) {\n+\t\trb = ring_buffer__new(map_fd, print_ringbuf_output, NULL, NULL);\n+\t\tif (!rb) {\n+\t\t\tp_err(\"failed to create ring buffer: %s (%d)\",\n+\t\t\t strerror(errno), errno);\n+\t\t\tgoto err_close_map;\n+\t\t}\n+\t} else {\n+\t\topts.cpu_cnt = ctx.all_cpus ? 0 : 1;\n+\t\topts.cpus = \u0026ctx.cpu;\n+\t\topts.map_keys = \u0026ctx.idx;\n+\t\tpb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, \u0026perf_attr,\n+\t\t\t\t\t print_bpf_output, \u0026ctx, \u0026opts);\n+\t\tif (!pb) {\n+\t\t\tp_err(\"failed to create perf buffer: %s (%d)\",\n+\t\t\t strerror(errno), errno);\n+\t\t\tgoto err_close_map;\n+\t\t}\n \t}\n \n \tsignal(SIGINT, int_exit);\n@@ -202,25 +239,33 @@ int do_event_pipe(int argc, char **argv)\n \tif (json_output)\n \t\tjsonw_start_array(json_wtr);\n \n+\terr = 0;\n \twhile (!stop) {\n-\t\terr = perf_buffer__poll(pb, 200);\n+\t\terr = rb ? ring_buffer__poll(rb, 200) : perf_buffer__poll(pb, 200);\n \t\tif (err \u003c 0 \u0026\u0026 err != -EINTR) {\n-\t\t\tp_err(\"perf buffer polling failed: %s (%d)\",\n-\t\t\t strerror(errno), errno);\n-\t\t\tgoto err_close_pb;\n+\t\t\tfprintf(stderr, \"Error: %s buffer polling failed: %s (%d)\\n\",\n+\t\t\t\trb ? \"ring\" : \"perf\", strerror(-err), -err);\n+\t\t\tbreak;\n \t\t}\n+\t\terr = 0;\n \t}\n \n+\tif (stop)\n+\t\tfprintf(stderr, \"Stopping...\\n\");\n \tif (json_output)\n \t\tjsonw_end_array(json_wtr);\n+\tif (fflush(stdout)) {\n+\t\tfprintf(stderr, \"Error: failed to write events: %s\\n\", strerror(errno));\n+\t\terr = -1;\n+\t}\n \n+\tring_buffer__free(rb);\n \tperf_buffer__free(pb);\n+\t/* Both buffer managers borrow map_fd. */\n \tclose(map_fd);\n \n-\treturn 0;\n+\treturn err \u003c 0 ? -1 : 0;\n \n-err_close_pb:\n-\tperf_buffer__free(pb);\n err_close_map:\n \tclose(map_fd);\n \treturn -1;\ndiff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_ringbuf.c b/tools/testing/selftests/bpf/prog_tests/bpftool_ringbuf.c\nnew file mode 100644\nindex 0000000000000..1a4ae88c05a07\n--- /dev/null\n+++ b/tools/testing/selftests/bpf/prog_tests/bpftool_ringbuf.c\n@@ -0,0 +1,425 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#include \u003cctype.h\u003e\n+#include \u003cfcntl.h\u003e\n+#include \u003cpoll.h\u003e\n+#include \u003csignal.h\u003e\n+#include \u003csys/mman.h\u003e\n+#include \u003csys/wait.h\u003e\n+#include \u003ctest_progs.h\u003e\n+#include \"bpftool_ringbuf.skel.h\"\n+\n+#define WAIT_STEPS 500\n+#define WAIT_US 10000\n+\n+struct consumer {\n+\tpid_t pid;\n+\tint fd;\n+};\n+\n+static const char *bpftool_path(void)\n+{\n+\tconst char *path = getenv(\"BPFTOOL\");\n+\n+\tif (path)\n+\t\treturn access(path, X_OK) ? NULL : path;\n+\tif (!access(\"./tools/sbin/bpftool\", X_OK))\n+\t\treturn \"./tools/sbin/bpftool\";\n+\tif (!access(\"../tools/sbin/bpftool\", X_OK))\n+\t\treturn \"../tools/sbin/bpftool\";\n+\treturn NULL;\n+}\n+\n+static void consumer_cleanup(struct consumer *child)\n+{\n+\tif (child-\u003epid \u003e 0) {\n+\t\tkill(child-\u003epid, SIGKILL);\n+\t\twhile (waitpid(child-\u003epid, NULL, 0) \u003c 0 \u0026\u0026 errno == EINTR)\n+\t\t\t;\n+\t\tchild-\u003epid = -1;\n+\t}\n+\tif (child-\u003efd \u003e= 0) {\n+\t\tclose(child-\u003efd);\n+\t\tchild-\u003efd = -1;\n+\t}\n+}\n+\n+static bool consumer_start(struct consumer *child, int map_fd, const char *format,\n+\t\t\t const char *pin_path, const char *option,\n+\t\t\t bool pair, bool capture_errors)\n+{\n+\tstruct bpf_map_info info = {};\n+\t__u32 len = sizeof(info);\n+\tconst char *path = bpftool_path();\n+\tchar *argv[12], id[16];\n+\tint out[2], ready[2], n = 0, err, err_fd;\n+\tstruct pollfd pfd;\n+\n+\tif (!ASSERT_OK_PTR(path, \"bpftool path (set BPFTOOL to override)\") ||\n+\t !ASSERT_OK(bpf_map_get_info_by_fd(map_fd, \u0026info, \u0026len), \"map info\"))\n+\t\treturn false;\n+\tsnprintf(id, sizeof(id), \"%u\", info.id);\n+\targv[n++] = (char *)path;\n+\tif (format)\n+\t\targv[n++] = (char *)format;\n+\targv[n++] = \"map\";\n+\targv[n++] = \"event_pipe\";\n+\targv[n++] = pin_path ? \"pinned\" : \"id\";\n+\targv[n++] = pin_path ? (char *)pin_path : id;\n+\tif (option) {\n+\t\targv[n++] = (char *)option;\n+\t\targv[n++] = \"0\";\n+\t\tif (pair) {\n+\t\t\targv[n++] = \"index\";\n+\t\t\targv[n++] = \"0\";\n+\t\t}\n+\t}\n+\targv[n] = NULL;\n+\tif (!ASSERT_OK(pipe2(out, O_CLOEXEC), \"output pipe\"))\n+\t\treturn false;\n+\tif (!ASSERT_OK(pipe2(ready, O_CLOEXEC), \"exec pipe\")) {\n+\t\tclose(out[0]);\n+\t\tclose(out[1]);\n+\t\treturn false;\n+\t}\n+\tchild-\u003epid = fork();\n+\tif (!child-\u003epid) {\n+\t\tclose(out[0]);\n+\t\tclose(ready[0]);\n+\t\terr_fd = capture_errors ? out[1] : open(\"/dev/null\", O_WRONLY);\n+\t\tif (dup2(out[1], STDOUT_FILENO) \u003c 0 ||\n+\t\t dup2(err_fd, STDERR_FILENO) \u003c 0)\n+\t\t\tgoto exec_fail;\n+\t\tif (!capture_errors)\n+\t\t\tclose(err_fd);\n+\t\tclose(out[1]);\n+\t\texecv(path, argv);\n+exec_fail:\n+\t\terr = errno;\n+\t\twrite(ready[1], \u0026err, sizeof(err));\n+\t\t_exit(127);\n+\t}\n+\tclose(out[1]);\n+\tclose(ready[1]);\n+\tchild-\u003efd = out[0];\n+\tpfd = (struct pollfd) { .fd = ready[0], .events = POLLIN };\n+\t/* EOF on the close-on-exec pipe distinguishes exec from inherited handlers. */\n+\terr = child-\u003epid \u003e 0 ? poll(\u0026pfd, 1, WAIT_STEPS * WAIT_US / 1000) : -1;\n+\tif (!ASSERT_GT(child-\u003epid, 0, \"fork\") ||\n+\t !ASSERT_GT(err, 0, \"exec timeout\") ||\n+\t !ASSERT_EQ(read(ready[0], \u0026err, sizeof(err)), 0, \"exec\")) {\n+\t\tclose(ready[0]);\n+\t\tconsumer_cleanup(child);\n+\t\treturn false;\n+\t}\n+\tclose(ready[0]);\n+\treturn true;\n+}\n+\n+static bool consumer_finish(struct consumer *child, int signo, bool success,\n+\t\t\t char *output, size_t size)\n+{\n+\tint status = 0, i;\n+\tpid_t ret = 0;\n+\tssize_t n;\n+\tsize_t used = 0;\n+\n+\tif (!ASSERT_OK(fcntl(child-\u003efd, F_SETFL, O_NONBLOCK), \"nonblocking output\"))\n+\t\treturn false;\n+\tif (signo \u0026\u0026 !ASSERT_OK(kill(child-\u003epid, signo), \"signal consumer\"))\n+\t\treturn false;\n+\tfor (i = 0; i \u003c WAIT_STEPS; i++) {\n+\t\twhile (used \u003c size - 1 \u0026\u0026\n+\t\t (n = read(child-\u003efd, output + used, size - 1 - used)) \u003e 0)\n+\t\t\tused += n;\n+\t\tret = waitpid(child-\u003epid, \u0026status, WNOHANG);\n+\t\tif (ret == child-\u003epid)\n+\t\t\tbreak;\n+\t\tif (ret \u003c 0 \u0026\u0026 errno != EINTR)\n+\t\t\tbreak;\n+\t\tusleep(WAIT_US);\n+\t}\n+\tif (!ASSERT_EQ(ret, child-\u003epid, \"bounded consumer exit\"))\n+\t\treturn false;\n+\tchild-\u003epid = -1;\n+\twhile (used \u003c size - 1 \u0026\u0026 (n = read(child-\u003efd, output + used, size - 1 - used)) \u003e 0)\n+\t\tused += n;\n+\toutput[used] = '\\0';\n+\treturn ASSERT_TRUE(WIFEXITED(status), \"normal exit\") \u0026\u0026\n+\t ASSERT_EQ(WEXITSTATUS(status) == 0, success, \"exit status\");\n+}\n+\n+static bool consumer_ready(struct consumer *child)\n+{\n+\tunsigned long long caught;\n+\tchar path[64], line[256];\n+\tint i;\n+\tFILE *f;\n+\n+\tsnprintf(path, sizeof(path), \"/proc/%d/status\", child-\u003epid);\n+\tfor (i = 0; i \u003c WAIT_STEPS; i++) {\n+\t\tf = fopen(path, \"r\");\n+\t\tif (!f)\n+\t\t\tbreak;\n+\t\twhile (fgets(line, sizeof(line), f)) {\n+\t\t\tif (sscanf(line, \"SigCgt: %llx\", \u0026caught) == 1 \u0026\u0026\n+\t\t\t (caught \u0026 (1ULL \u003c\u003c (SIGINT - 1))) \u0026\u0026\n+\t\t\t (caught \u0026 (1ULL \u003c\u003c (SIGTERM - 1)))) {\n+\t\t\t\tfclose(f);\n+\t\t\t\treturn true;\n+\t\t\t}\n+\t\t}\n+\t\tfclose(f);\n+\t\tusleep(WAIT_US);\n+\t}\n+\treturn ASSERT_TRUE(false, \"consumer signal handlers ready\");\n+}\n+\n+static bool emit_record(struct bpftool_ringbuf *skel, int record)\n+{\n+\tchar packet[64] = {};\n+\n+\tLIBBPF_OPTS(bpf_test_run_opts, opts,\n+\t\t .data_in = packet,\n+\t\t .data_size_in = sizeof(packet),\n+\t);\n+\n+\tskel-\u003ebss-\u003erecord = record;\n+\treturn ASSERT_OK(bpf_prog_test_run_opts(bpf_program__fd(skel-\u003eprogs.produce),\n+\t\t\t\t\t \u0026opts), \"produce record\") \u0026\u0026\n+\t ASSERT_OK(skel-\u003ebss-\u003eoutput_err, \"ringbuf output\");\n+}\n+\n+static bool consumed(unsigned long *position, unsigned long expected)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i \u003c WAIT_STEPS; i++) {\n+\t\tif (__atomic_load_n(position, __ATOMIC_ACQUIRE) == expected)\n+\t\t\treturn true;\n+\t\tusleep(WAIT_US);\n+\t}\n+\treturn ASSERT_EQ(*position, expected, \"consumer position\");\n+}\n+\n+static void check_json(char *output, const char *expected)\n+{\n+\tchar *src = output, *dst = output;\n+\tbool quoted = false, escaped = false;\n+\n+\t/* Ignore formatting whitespace while checking the entire JSON document. */\n+\twhile (*src) {\n+\t\tif (quoted || !isspace((unsigned char)*src))\n+\t\t\t*dst++ = *src;\n+\t\tif (!escaped \u0026\u0026 *src == '\"')\n+\t\t\tquoted = !quoted;\n+\t\tescaped = !escaped \u0026\u0026 quoted \u0026\u0026 *src == '\\\\';\n+\t\tsrc++;\n+\t}\n+\t*dst = '\\0';\n+\tASSERT_STREQ(output, expected, \"JSON records\");\n+}\n+\n+static void test_consumer(const char *format, bool idle, int signo, bool pinned)\n+{\n+\tstruct consumer child = { .pid = -1, .fd = -1 };\n+\tstruct bpftool_ringbuf *skel;\n+\tunsigned long *position = MAP_FAILED;\n+\tint page_size = getpagesize(), fd;\n+\tchar pin_dir[] = \"/sys/fs/bpf/bpftool_ringbuf_XXXXXX\";\n+\tchar pin_path[sizeof(pin_dir) + sizeof(\"/map\")];\n+\tbool dir_created = false, map_pinned = false;\n+\tchar output[4096];\n+\tstruct pollfd pfd;\n+\n+\tskel = bpftool_ringbuf__open();\n+\tif (!ASSERT_OK_PTR(skel, \"open\"))\n+\t\treturn;\n+\tbpf_map__set_max_entries(skel-\u003emaps.ringbuf, page_size);\n+\tif (!ASSERT_OK(bpftool_ringbuf__load(skel), \"load\"))\n+\t\tgoto out;\n+\tfd = bpf_map__fd(skel-\u003emaps.ringbuf);\n+\tif (pinned) {\n+\t\tif (!ASSERT_OK_PTR(mkdtemp(pin_dir), \"create pin directory\"))\n+\t\t\tgoto out;\n+\t\tdir_created = true;\n+\t\tsnprintf(pin_path, sizeof(pin_path), \"%s/map\", pin_dir);\n+\t\tif (!ASSERT_OK(bpf_obj_pin(fd, pin_path), \"pin ringbuf\"))\n+\t\t\tgoto out;\n+\t\tmap_pinned = true;\n+\t}\n+\tposition = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);\n+\tif (!ASSERT_NEQ(position, MAP_FAILED, \"consumer mmap\"))\n+\t\tgoto out;\n+\tif (!idle \u0026\u0026 (!emit_record(skel, 0) || !emit_record(skel, 1)))\n+\t\tgoto out;\n+\tif (!consumer_start(\u0026child, fd, format, pinned ? pin_path : NULL,\n+\t\t\t NULL, false, false) ||\n+\t !consumer_ready(\u0026child))\n+\t\tgoto out;\n+\tif (!idle) {\n+\t\t/* Both prefilled records occupy 16 bytes including their headers. */\n+\t\tif (!consumed(position, 32))\n+\t\t\tgoto out;\n+\t\tpfd = (struct pollfd) { .fd = child.fd, .events = POLLIN };\n+\t\tif (!ASSERT_GT(poll(\u0026pfd, 1, WAIT_STEPS * WAIT_US / 1000), 0,\n+\t\t\t \"records flushed before exit\") ||\n+\t\t !ASSERT_TRUE(pfd.revents \u0026 POLLIN, \"record output readable\") ||\n+\t\t !emit_record(skel, 2) || !consumed(position, 64))\n+\t\t\tgoto out;\n+\t}\n+\tif (!consumer_finish(\u0026child, signo, true, output, sizeof(output)))\n+\t\tgoto out;\n+\tif (format \u0026\u0026 !strcmp(format, \"-p\"))\n+\t\tASSERT_STREQ(output, idle ? \"[]\\n\" :\n+\t\t\t \"[{\\n\"\n+\t\t\t \" \\\"size\\\": 2,\\n\"\n+\t\t\t \" \\\"data\\\": [0,255\\n\"\n+\t\t\t \" ]\\n\"\n+\t\t\t \" },{\\n\"\n+\t\t\t \" \\\"size\\\": 5,\\n\"\n+\t\t\t \" \\\"data\\\": [1,2,3,4,5\\n\"\n+\t\t\t \" ]\\n\"\n+\t\t\t \" },{\\n\"\n+\t\t\t \" \\\"size\\\": 17,\\n\"\n+\t\t\t \" \\\"data\\\": [16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32\\n\"\n+\t\t\t \" ]\\n\"\n+\t\t\t \" }\\n\"\n+\t\t\t \"]\\n\", \"pretty JSON records\");\n+\telse if (format)\n+\t\tcheck_json(output, idle ? \"[]\" :\n+\t\t\t \"[{\\\"size\\\":2,\\\"data\\\":[0,255]},\"\n+\t\t\t \"{\\\"size\\\":5,\\\"data\\\":[1,2,3,4,5]},\"\n+\t\t\t \"{\\\"size\\\":17,\\\"data\\\":[16,17,18,19,20,21,22,23,\"\n+\t\t\t \"24,25,26,27,28,29,30,31,32]}]\");\n+\telse\n+\t\tASSERT_STREQ(output, idle ? \"\" :\n+\t\t\t \"== size: 2 =====\\n00 ff\\n\"\n+\t\t\t \"== size: 5 =====\\n01 02 03 04 05\\n\"\n+\t\t\t \"== size: 17 =====\\n10 11 12 13 14 15 16 17 \"\n+\t\t\t \"18 19 1a 1b 1c 1d 1e 1f\\n20\\n\", \"plain records\");\n+out:\n+\tconsumer_cleanup(\u0026child);\n+\tif (position != MAP_FAILED)\n+\t\tmunmap(position, page_size);\n+\tif (map_pinned)\n+\t\tASSERT_OK(unlink(pin_path), \"unpin ringbuf\");\n+\tif (dir_created)\n+\t\tASSERT_OK(rmdir(pin_dir), \"remove pin directory\");\n+\tbpftool_ringbuf__destroy(skel);\n+}\n+\n+static void test_perf_consumer(void)\n+{\n+\tstruct consumer child = { .pid = -1, .fd = -1 };\n+\tunsigned long long seconds, nanoseconds;\n+\tstruct bpftool_ringbuf *skel;\n+\tchar output[16384], expected[16384];\n+\tint nr_cpus, cpu, index, offset = 0, i, used = 0, fields;\n+\tstruct pollfd pfd;\n+\n+\tnr_cpus = libbpf_num_possible_cpus();\n+\tif (!ASSERT_GT(nr_cpus, 0, \"possible cpus\"))\n+\t\treturn;\n+\tskel = bpftool_ringbuf__open();\n+\tif (!ASSERT_OK_PTR(skel, \"open\"))\n+\t\treturn;\n+\tbpf_map__set_max_entries(skel-\u003emaps.ringbuf, getpagesize());\n+\tbpf_map__set_max_entries(skel-\u003emaps.perfbuf, nr_cpus);\n+\tif (!ASSERT_OK(bpftool_ringbuf__load(skel), \"load\") ||\n+\t !consumer_start(\u0026child, bpf_map__fd(skel-\u003emaps.perfbuf), NULL,\n+\t\t\t NULL, NULL, false, false) || !consumer_ready(\u0026child) ||\n+\t !emit_record(skel, 3))\n+\t\tgoto out;\n+\t/* One large record flushes the existing buffered perf output callback. */\n+\tpfd = (struct pollfd) { .fd = child.fd, .events = POLLIN };\n+\tif (!ASSERT_GT(poll(\u0026pfd, 1, WAIT_STEPS * WAIT_US / 1000), 0,\n+\t\t \"perf record output\") ||\n+\t !ASSERT_TRUE(pfd.revents \u0026 POLLIN, \"perf output readable\") ||\n+\t !consumer_finish(\u0026child, SIGINT, true, output, sizeof(output)))\n+\t\tgoto out;\n+\tfields = sscanf(output, \"== @%llu.%llu CPU: %d index: %d =====\\n%n\",\n+\t\t\t\u0026seconds, \u0026nanoseconds, \u0026cpu, \u0026index, \u0026offset);\n+\tif (!ASSERT_EQ(fields, 4, \"perf header\") ||\n+\t !ASSERT_GT(offset, 0, \"perf payload offset\"))\n+\t\tgoto out;\n+\tASSERT_GT(seconds * 1000000000ULL + nanoseconds, 0, \"perf timestamp\");\n+\tASSERT_LT(nanoseconds, 1000000000ULL, \"perf timestamp nanoseconds\");\n+\tASSERT_GE(cpu, 0, \"perf cpu\");\n+\tASSERT_LT(cpu, nr_cpus, \"perf cpu range\");\n+\tASSERT_EQ(index, cpu, \"perf index\");\n+\tfor (i = 0; i \u003c sizeof(skel-\u003erodata-\u003eperf_payload); i++) {\n+\t\tconst char *separator = !i ? \"\" : !(i % 16) ? \"\\n\" :\n+\t\t\t\t\t!(i % 8) ? \" \" : \" \";\n+\n+\t\tused += snprintf(expected + used, sizeof(expected) - used,\n+\t\t\t\t \"%s%02x\", separator, i == 1 ? 0xff : 0);\n+\t}\n+\tsnprintf(expected + used, sizeof(expected) - used, \"\\n\");\n+\tASSERT_STREQ(output + offset, expected, \"perf payload\");\n+out:\n+\tconsumer_cleanup(\u0026child);\n+\tbpftool_ringbuf__destroy(skel);\n+}\n+\n+static void test_reject(enum bpf_map_type type, const char *option, bool pair, bool json)\n+{\n+\tstruct consumer child = { .pid = -1, .fd = -1 };\n+\tbool ring = type == BPF_MAP_TYPE_RINGBUF || type == BPF_MAP_TYPE_USER_RINGBUF;\n+\tconst char *expected = option ?\n+\t\t\"{\\\"error\\\":\\\"ring buffer maps do not support cpu or index arguments\\\"}\" :\n+\t\t\"{\\\"error\\\":\\\"map is not a perf event array or ring buffer\\\"}\";\n+\tchar output[4096];\n+\tint fd;\n+\n+\tfd = bpf_map_create(type, NULL, ring ? 0 : 4, ring ? 0 : 4,\n+\t\t\t ring ? getpagesize() : 1, NULL);\n+\tif (!ASSERT_GE(fd, 0, \"create map\"))\n+\t\treturn;\n+\tif (consumer_start(\u0026child, fd, json ? \"-j\" : NULL, NULL, option, pair, true) \u0026\u0026\n+\t consumer_finish(\u0026child, 0, false, output, sizeof(output))) {\n+\t\tif (json)\n+\t\t\tcheck_json(output, expected);\n+\t\telse\n+\t\t\tASSERT_GT(strlen(output), 0, \"error diagnostic\");\n+\t}\n+\tconsumer_cleanup(\u0026child);\n+\tclose(fd);\n+}\n+\n+void test_bpftool_ringbuf(void)\n+{\n+\tif (test__start_subtest(\"perf_event_array\"))\n+\t\ttest_perf_consumer();\n+\tif (test__start_subtest(\"plain\"))\n+\t\ttest_consumer(NULL, false, SIGINT, false);\n+\tif (test__start_subtest(\"json\"))\n+\t\ttest_consumer(\"-j\", false, SIGTERM, false);\n+\tif (test__start_subtest(\"pretty_json\"))\n+\t\ttest_consumer(\"-p\", false, SIGINT, false);\n+\tif (test__start_subtest(\"pinned_plain\"))\n+\t\ttest_consumer(NULL, false, SIGTERM, true);\n+\tif (test__start_subtest(\"pinned_json\"))\n+\t\ttest_consumer(\"-j\", false, SIGINT, true);\n+\tif (test__start_subtest(\"pinned_pretty_json\"))\n+\t\ttest_consumer(\"-p\", false, SIGTERM, true);\n+\tif (test__start_subtest(\"idle_sigint\"))\n+\t\ttest_consumer(NULL, true, SIGINT, false);\n+\tif (test__start_subtest(\"idle_sigterm_json\"))\n+\t\ttest_consumer(\"-j\", true, SIGTERM, false);\n+\tif (test__start_subtest(\"idle_sigint_pretty_json\"))\n+\t\ttest_consumer(\"-p\", true, SIGINT, false);\n+\tif (test__start_subtest(\"reject_array\"))\n+\t\ttest_reject(BPF_MAP_TYPE_ARRAY, NULL, false, false);\n+\tif (test__start_subtest(\"reject_user_ringbuf\"))\n+\t\ttest_reject(BPF_MAP_TYPE_USER_RINGBUF, NULL, false, false);\n+\tif (test__start_subtest(\"reject_cpu\"))\n+\t\ttest_reject(BPF_MAP_TYPE_RINGBUF, \"cpu\", false, false);\n+\tif (test__start_subtest(\"reject_index\"))\n+\t\ttest_reject(BPF_MAP_TYPE_RINGBUF, \"index\", false, false);\n+\tif (test__start_subtest(\"reject_cpu_index\"))\n+\t\ttest_reject(BPF_MAP_TYPE_RINGBUF, \"cpu\", true, false);\n+\tif (test__start_subtest(\"reject_user_ringbuf_json\"))\n+\t\ttest_reject(BPF_MAP_TYPE_USER_RINGBUF, NULL, false, true);\n+\tif (test__start_subtest(\"reject_cpu_index_json\"))\n+\t\ttest_reject(BPF_MAP_TYPE_RINGBUF, \"cpu\", true, true);\n+}\ndiff --git a/tools/testing/selftests/bpf/progs/bpftool_ringbuf.c b/tools/testing/selftests/bpf/progs/bpftool_ringbuf.c\nnew file mode 100644\nindex 0000000000000..bbbc93c30a833\n--- /dev/null\n+++ b/tools/testing/selftests/bpf/progs/bpftool_ringbuf.c\n@@ -0,0 +1,47 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#include \u003clinux/bpf.h\u003e\n+#include \u003cbpf/bpf_helpers.h\u003e\n+\n+struct {\n+\t__uint(type, BPF_MAP_TYPE_RINGBUF);\n+} ringbuf SEC(\".maps\");\n+\n+struct {\n+\t__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);\n+\t__uint(key_size, sizeof(__u32));\n+\t__uint(value_size, sizeof(__u32));\n+\t__uint(max_entries, 1);\n+} perfbuf SEC(\".maps\");\n+\n+/*\n+ * Include the u32 raw size in perf's 8-byte alignment to avoid padding.\n+ * Keep plain output large enough to flush stdio before the consumer exits.\n+ */\n+const unsigned char perf_payload[4092] = { 0x00, 0xff };\n+\n+int record;\n+int output_err;\n+\n+SEC(\"socket\")\n+int produce(struct __sk_buff *skb)\n+{\n+\tunsigned char first[] = { 0x00, 0xff };\n+\tunsigned char second[] = { 1, 2, 3, 4, 5 };\n+\tunsigned char third[] = {\n+\t\t0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n+\t\t0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,\n+\t};\n+\n+\tif (record == 0)\n+\t\toutput_err = bpf_ringbuf_output(\u0026ringbuf, first, sizeof(first), 0);\n+\telse if (record == 1)\n+\t\toutput_err = bpf_ringbuf_output(\u0026ringbuf, second, sizeof(second), 0);\n+\telse if (record == 2)\n+\t\toutput_err = bpf_ringbuf_output(\u0026ringbuf, third, sizeof(third), 0);\n+\telse\n+\t\toutput_err = bpf_perf_event_output(skb, \u0026perfbuf, BPF_F_CURRENT_CPU,\n+\t\t\t\t\t\t (void *)perf_payload, sizeof(perf_payload));\n+\treturn 0;\n+}\n+\n+char LICENSE[] SEC(\"license\") = \"GPL\";\n"
} |
| 2/1 | 2026/09/11 03:00 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The changes are strictly limited to user-space utilities (bpftool under tools/bpf/bpftool/) and selftests (tools/testing/selftests/bpf/). No kernel-space code or compiled kernel image (vmlinux/modules) is modified.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit d3ae3d9e355eb860db6da7ef33e14759f6b658c7
Author: syz-cluster <triage@syzkaller.com>
Date: Fri Sep 11 03:00:01 2026 +0000
syz-cluster: applied patch under review
diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
index 5daf3de5c7446..e4ed7e701c9e4 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
@@ -120,7 +120,8 @@ bpftool map pin *MAP* *FILE*
character ('.'), which is reserved for future extensions of *bpffs*.
bpftool map event_pipe *MAP* [cpu *N* index *M*]
- Read events from a **BPF_MAP_TYPE_PERF_EVENT_ARRAY** map.
+ Read events from a **BPF_MAP_TYPE_PERF_EVENT_ARRAY** or
+ **BPF_MAP_TYPE_RINGBUF** map.
Install perf rings into a perf event array map and dump output of any
**bpf_perf_event_output**\ () call in the kernel. By default read the
@@ -134,6 +135,17 @@ bpftool map event_pipe *MAP* [cpu *N* index *M*]
existing ring. Any other application will stop receiving events if it
installed its rings earlier.
+ For a ring buffer map, consume records submitted by BPF programs, including
+ records already queued before the command starts. **cpu** and **index**
+ are not supported. Each record is printed in full, including embedded zero
+ bytes. Plain output reports the record size followed by hexadecimal
+ bytes; JSON output contains **size** and **data** fields, with **data** an
+ array of byte values. Ring buffer records have no implicit CPU or timestamp.
+
+ Consuming a ring buffer advances its shared consumer position, so this
+ command must not run alongside another consumer of the same map.
+ **BPF_MAP_TYPE_USER_RINGBUF** maps are not supported.
+
bpftool map peek *MAP*
Peek next value in the queue or stack.
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 75cbcb512ebae..1750b488c9e3b 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -878,11 +878,11 @@ _bpftool()
return 0
;;
id)
- _bpftool_get_map_ids_for_type perf_event_array
+ _bpftool_get_map_ids_for_type '"type": "\(perf_event_array\|ringbuf\)"'
return 0
;;
name)
- _bpftool_get_map_names_for_type perf_event_array
+ _bpftool_get_map_names_for_type '"type": "\(perf_event_array\|ringbuf\)"'
return 0
;;
cpu)
diff --git a/tools/bpf/bpftool/map_perf_ring.c b/tools/bpf/bpftool/map_perf_ring.c
index bcb767e2d6733..7d555331f443a 100644
--- a/tools/bpf/bpftool/map_perf_ring.c
+++ b/tools/bpf/bpftool/map_perf_ring.c
@@ -27,7 +27,7 @@
#define MMAP_PAGE_CNT 16
-static volatile bool stop;
+static volatile sig_atomic_t stop;
struct perf_event_sample {
struct perf_event_header header;
@@ -44,7 +44,6 @@ struct perf_event_lost {
static void int_exit(int signo)
{
- fprintf(stderr, "Stopping...\n");
stop = true;
}
@@ -107,6 +106,27 @@ print_bpf_output(void *private_data, int cpu, struct perf_event_header *event)
return LIBBPF_PERF_EVENT_CONT;
}
+static int print_ringbuf_output(void *ctx, void *data, size_t size)
+{
+ if (json_output) {
+ jsonw_start_object(json_wtr);
+ jsonw_uint_field(json_wtr, "size", size);
+ jsonw_name(json_wtr, "data");
+ print_data_json(data, size);
+ jsonw_end_object(json_wtr);
+ } else {
+ printf("== size: %zu =====\n", size);
+ fprint_hex(stdout, data, size, " ");
+ printf("\n");
+ }
+
+ if (fflush(stdout))
+ return errno ? -errno : -EIO;
+
+ /* A producer can keep poll() busy even after a signal arrives. */
+ return stop ? -EINTR : 0;
+}
+
int do_event_pipe(int argc, char **argv)
{
struct perf_event_attr perf_attr = {
@@ -123,18 +143,26 @@ int do_event_pipe(int argc, char **argv)
.cpu = -1,
.idx = -1,
};
- struct perf_buffer *pb;
+ struct perf_buffer *pb = NULL;
+ struct ring_buffer *rb = NULL;
__u32 map_info_len;
int err, map_fd;
+ stop = false;
map_info_len = sizeof(map_info);
map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len,
0);
if (map_fd < 0)
return -1;
- if (map_info.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
- p_err("map is not a perf event array");
+ if (map_info.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY &&
+ map_info.type != BPF_MAP_TYPE_RINGBUF) {
+ p_err("map is not a perf event array or ring buffer");
+ goto err_close_map;
+ }
+
+ if (map_info.type == BPF_MAP_TYPE_RINGBUF && argc) {
+ p_err("ring buffer maps do not support cpu or index arguments");
goto err_close_map;
}
@@ -184,15 +212,24 @@ int do_event_pipe(int argc, char **argv)
ctx.idx = 0;
}
- opts.cpu_cnt = ctx.all_cpus ? 0 : 1;
- opts.cpus = &ctx.cpu;
- opts.map_keys = &ctx.idx;
- pb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, &perf_attr,
- print_bpf_output, &ctx, &opts);
- if (!pb) {
- p_err("failed to create perf buffer: %s (%d)",
- strerror(errno), errno);
- goto err_close_map;
+ if (map_info.type == BPF_MAP_TYPE_RINGBUF) {
+ rb = ring_buffer__new(map_fd, print_ringbuf_output, NULL, NULL);
+ if (!rb) {
+ p_err("failed to create ring buffer: %s (%d)",
+ strerror(errno), errno);
+ goto err_close_map;
+ }
+ } else {
+ opts.cpu_cnt = ctx.all_cpus ? 0 : 1;
+ opts.cpus = &ctx.cpu;
+ opts.map_keys = &ctx.idx;
+ pb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, &perf_attr,
+ print_bpf_output, &ctx, &opts);
+ if (!pb) {
+ p_err("failed to create perf buffer: %s (%d)",
+ strerror(errno), errno);
+ goto err_close_map;
+ }
}
signal(SIGINT, int_exit);
@@ -202,25 +239,33 @@ int do_event_pipe(int argc, char **argv)
if (json_output)
jsonw_start_array(json_wtr);
+ err = 0;
while (!stop) {
- err = perf_buffer__poll(pb, 200);
+ err = rb ? ring_buffer__poll(rb, 200) : perf_buffer__poll(pb, 200);
if (err < 0 && err != -EINTR) {
- p_err("perf buffer polling failed: %s (%d)",
- strerror(errno), errno);
- goto err_close_pb;
+ fprintf(stderr, "Error: %s buffer polling failed: %s (%d)\n",
+ rb ? "ring" : "perf", strerror(-err), -err);
+ break;
}
+ err = 0;
}
+ if (stop)
+ fprintf(stderr, "Stopping...\n");
if (json_output)
jsonw_end_array(json_wtr);
+ if (fflush(stdout)) {
+ fprintf(stderr, "Error: failed to write events: %s\n", strerror(errno));
+ err = -1;
+ }
+ ring_buffer__free(rb);
perf_buffer__free(pb);
+ /* Both buffer managers borrow map_fd. */
close(map_fd);
- return 0;
+ return err < 0 ? -1 : 0;
-err_close_pb:
- perf_buffer__free(pb);
err_close_map:
close(map_fd);
return -1;
diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_ringbuf.c b/tools/testing/selftests/bpf/prog_tests/bpftool_ringbuf.c
new file mode 100644
index 0000000000000..1a4ae88c05a07
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/bpftool_ringbuf.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <ctype.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <test_progs.h>
+#include "bpftool_ringbuf.skel.h"
+
+#define WAIT_STEPS 500
+#define WAIT_US 10000
+
+struct consumer {
+ pid_t pid;
+ int fd;
+};
+
+static const char *bpftool_path(void)
+{
+ const char *path = getenv("BPFTOOL");
+
+ if (path)
+ return access(path, X_OK) ? NULL : path;
+ if (!access("./tools/sbin/bpftool", X_OK))
+ return "./tools/sbin/bpftool";
+ if (!access("../tools/sbin/bpftool", X_OK))
+ return "../tools/sbin/bpftool";
+ return NULL;
+}
+
+static void consumer_cleanup(struct consumer *child)
+{
+ if (child->pid > 0) {
+ kill(child->pid, SIGKILL);
+ while (waitpid(child->pid, NULL, 0) < 0 && errno == EINTR)
+ ;
+ child->pid = -1;
+ }
+ if (child->fd >= 0) {
+ close(child->fd);
+ child->fd = -1;
+ }
+}
+
+static bool consumer_start(struct consumer *child, int map_fd, const char *format,
+ const char *pin_path, const char *option,
+ bool pair, bool capture_errors)
+{
+ struct bpf_map_info info = {};
+ __u32 len = sizeof(info);
+ const char *path = bpftool_path();
+ char *argv[12], id[16];
+ int out[2], ready[2], n = 0, err, err_fd;
+ struct pollfd pfd;
+
+ if (!ASSERT_OK_PTR(path, "bpftool path (set BPFTOOL to override)") ||
+ !ASSERT_OK(bpf_map_get_info_by_fd(map_fd, &info, &len), "map info"))
+ return false;
+ snprintf(id, sizeof(id), "%u", info.id);
+ argv[n++] = (char *)path;
+ if (format)
+ argv[n++] = (char *)format;
+ argv[n++] = "map";
+ argv[n++] = "event_pipe";
+ argv[n++] = pin_path ? "pinned" : "id";
+ argv[n++] = pin_path ? (char *)pin_path : id;
+ if (option) {
+ argv[n++] = (char *)option;
+ argv[n++] = "0";
+ if (pair) {
+ argv[n++] = "index";
+ argv[n++] = "0";
+ }
+ }
+ argv[n] = NULL;
+ if (!ASSERT_OK(pipe2(out, O_CLOEXEC), "output pipe"))
+ return false;
+ if (!ASSERT_OK(pipe2(ready, O_CLOEXEC), "exec pipe")) {
+ close(out[0]);
+ close(out[1]);
+ return false;
+ }
+ child->pid = fork();
+ if (!child->pid) {
+ close(out[0]);
+ close(ready[0]);
+ err_fd = capture_errors ? out[1] : open("/dev/null", O_WRONLY);
+ if (dup2(out[1], STDOUT_FILENO) < 0 ||
+ dup2(err_fd, STDERR_FILENO) < 0)
+ goto exec_fail;
+ if (!capture_errors)
+ close(err_fd);
+ close(out[1]);
+ execv(path, argv);
+exec_fail:
+ err = errno;
+ write(ready[1], &err, sizeof(err));
+ _exit(127);
+ }
+ close(out[1]);
+ close(ready[1]);
+ child->fd = out[0];
+ pfd = (struct pollfd) { .fd = ready[0], .events = POLLIN };
+ /* EOF on the close-on-exec pipe distinguishes exec from inherited handlers. */
+ err = child->pid > 0 ? poll(&pfd, 1, WAIT_STEPS * WAIT_US / 1000) : -1;
+ if (!ASSERT_GT(child->pid, 0, "fork") ||
+ !ASSERT_GT(err, 0, "exec timeout") ||
+ !ASSERT_EQ(read(ready[0], &err, sizeof(err)), 0, "exec")) {
+ close(ready[0]);
+ consumer_cleanup(child);
+ return false;
+ }
+ close(ready[0]);
+ return true;
+}
+
+static bool consumer_finish(struct consumer *child, int signo, bool success,
+ char *output, size_t size)
+{
+ int status = 0, i;
+ pid_t ret = 0;
+ ssize_t n;
+ size_t used = 0;
+
+ if (!ASSERT_OK(fcntl(child->fd, F_SETFL, O_NONBLOCK), "nonblocking output"))
+ return false;
+ if (signo && !ASSERT_OK(kill(child->pid, signo), "signal consumer"))
+ return false;
+ for (i = 0; i < WAIT_STEPS; i++) {
+ while (used < size - 1 &&
+ (n = read(child->fd, output + used, size - 1 - used)) > 0)
+ used += n;
+ ret = waitpid(child->pid, &status, WNOHANG);
+ if (ret == child->pid)
+ break;
+ if (ret < 0 && errno != EINTR)
+ break;
+ usleep(WAIT_US);
+ }
+ if (!ASSERT_EQ(ret, child->pid, "bounded consumer exit"))
+ return false;
+ child->pid = -1;
+ while (used < size - 1 && (n = read(child->fd, output + used, size - 1 - used)) > 0)
+ used += n;
+ output[used] = '\0';
+ return ASSERT_TRUE(WIFEXITED(status), "normal exit") &&
+ ASSERT_EQ(WEXITSTATUS(status) == 0, success, "exit status");
+}
+
+static bool consumer_ready(struct consumer *child)
+{
+ unsigned long long caught;
+ char path[64], line[256];
+ int i;
+ FILE *f;
+
+ snprintf(path, sizeof(path), "/proc/%d/status", child->pid);
+ for (i = 0; i < WAIT_STEPS; i++) {
+ f = fopen(path, "r");
+ if (!f)
+ break;
+ while (fgets(line, sizeof(line), f)) {
+ if (sscanf(line, "SigCgt: %llx", &caught) == 1 &&
+ (caught & (1ULL << (SIGINT - 1))) &&
+ (caught & (1ULL << (SIGTERM - 1)))) {
+ fclose(f);
+ return true;
+ }
+ }
+ fclose(f);
+ usleep(WAIT_US);
+ }
+ return ASSERT_TRUE(false, "consumer signal handlers ready");
+}
+
+static bool emit_record(struct bpftool_ringbuf *skel, int record)
+{
+ char packet[64] = {};
+
+ LIBBPF_OPTS(bpf_test_run_opts, opts,
+ .data_in = packet,
+ .data_size_in = sizeof(packet),
+ );
+
+ skel->bss->record = record;
+ return ASSERT_OK(bpf_prog_test_run_opts(bpf_program__fd(skel->progs.produce),
+ &opts), "produce record") &&
+ ASSERT_OK(skel->bss->output_err, "ringbuf output");
+}
+
+static bool consumed(unsigned long *position, unsigned long expected)
+{
+ int i;
+
+ for (i = 0; i < WAIT_STEPS; i++) {
+ if (__atomic_load_n(position, __ATOMIC_ACQUIRE) == expected)
+ return true;
+ usleep(WAIT_US);
+ }
+ return ASSERT_EQ(*position, expected, "consumer position");
+}
+
+static void check_json(char *output, const char *expected)
+{
+ char *src = output, *dst = output;
+ bool quoted = false, escaped = false;
+
+ /* Ignore formatting whitespace while checking the entire JSON document. */
+ while (*src) {
+ if (quoted || !isspace((unsigned char)*src))
+ *dst++ = *src;
+ if (!escaped && *src == '"')
+ quoted = !quoted;
+ escaped = !escaped && quoted && *src == '\\';
+ src++;
+ }
+ *dst = '\0';
+ ASSERT_STREQ(output, expected, "JSON records");
+}
+
+static void test_consumer(const char *format, bool idle, int signo, bool pinned)
+{
+ struct consumer child = { .pid = -1, .fd = -1 };
+ struct bpftool_ringbuf *skel;
+ unsigned long *position = MAP_FAILED;
+ int page_size = getpagesize(), fd;
+ char pin_dir[] = "/sys/fs/bpf/bpftool_ringbuf_XXXXXX";
+ char pin_path[sizeof(pin_dir) + sizeof("/map")];
+ bool dir_created = false, map_pinned = false;
+ char output[4096];
+ struct pollfd pfd;
+
+ skel = bpftool_ringbuf__open();
+ if (!ASSERT_OK_PTR(skel, "open"))
+ return;
+ bpf_map__set_max_entries(skel->maps.ringbuf, page_size);
+ if (!ASSERT_OK(bpftool_ringbuf__load(skel), "load"))
+ goto out;
+ fd = bpf_map__fd(skel->maps.ringbuf);
+ if (pinned) {
+ if (!ASSERT_OK_PTR(mkdtemp(pin_dir), "create pin directory"))
+ goto out;
+ dir_created = true;
+ snprintf(pin_path, sizeof(pin_path), "%s/map", pin_dir);
+ if (!ASSERT_OK(bpf_obj_pin(fd, pin_path), "pin ringbuf"))
+ goto out;
+ map_pinned = true;
+ }
+ position = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!ASSERT_NEQ(position, MAP_FAILED, "consumer mmap"))
+ goto out;
+ if (!idle && (!emit_record(skel, 0) || !emit_record(skel, 1)))
+ goto out;
+ if (!consumer_start(&child, fd, format, pinned ? pin_path : NULL,
+ NULL, false, false) ||
+ !consumer_ready(&child))
+ goto out;
+ if (!idle) {
+ /* Both prefilled records occupy 16 bytes including their headers. */
+ if (!consumed(position, 32))
+ goto out;
+ pfd = (struct pollfd) { .fd = child.fd, .events = POLLIN };
+ if (!ASSERT_GT(poll(&pfd, 1, WAIT_STEPS * WAIT_US / 1000), 0,
+ "records flushed before exit") ||
+ !ASSERT_TRUE(pfd.revents & POLLIN, "record output readable") ||
+ !emit_record(skel, 2) || !consumed(position, 64))
+ goto out;
+ }
+ if (!consumer_finish(&child, signo, true, output, sizeof(output)))
+ goto out;
+ if (format && !strcmp(format, "-p"))
+ ASSERT_STREQ(output, idle ? "[]\n" :
+ "[{\n"
+ " \"size\": 2,\n"
+ " \"data\": [0,255\n"
+ " ]\n"
+ " },{\n"
+ " \"size\": 5,\n"
+ " \"data\": [1,2,3,4,5\n"
+ " ]\n"
+ " },{\n"
+ " \"size\": 17,\n"
+ " \"data\": [16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32\n"
+ " ]\n"
+ " }\n"
+ "]\n", "pretty JSON records");
+ else if (format)
+ check_json(output, idle ? "[]" :
+ "[{\"size\":2,\"data\":[0,255]},"
+ "{\"size\":5,\"data\":[1,2,3,4,5]},"
+ "{\"size\":17,\"data\":[16,17,18,19,20,21,22,23,"
+ "24,25,26,27,28,29,30,31,32]}]");
+ else
+ ASSERT_STREQ(output, idle ? "" :
+ "== size: 2 =====\n00 ff\n"
+ "== size: 5 =====\n01 02 03 04 05\n"
+ "== size: 17 =====\n10 11 12 13 14 15 16 17 "
+ "18 19 1a 1b 1c 1d 1e 1f\n20\n", "plain records");
+out:
+ consumer_cleanup(&child);
+ if (position != MAP_FAILED)
+ munmap(position, page_size);
+ if (map_pinned)
+ ASSERT_OK(unlink(pin_path), "unpin ringbuf");
+ if (dir_created)
+ ASSERT_OK(rmdir(pin_dir), "remove pin directory");
+ bpftool_ringbuf__destroy(skel);
+}
+
+static void test_perf_consumer(void)
+{
+ struct consumer child = { .pid = -1, .fd = -1 };
+ unsigned long long seconds, nanoseconds;
+ struct bpftool_ringbuf *skel;
+ char output[16384], expected[16384];
+ int nr_cpus, cpu, index, offset = 0, i, used = 0, fields;
+ struct pollfd pfd;
+
+ nr_cpus = libbpf_num_possible_cpus();
+ if (!ASSERT_GT(nr_cpus, 0, "possible cpus"))
+ return;
+ skel = bpftool_ringbuf__open();
+ if (!ASSERT_OK_PTR(skel, "open"))
+ return;
+ bpf_map__set_max_entries(skel->maps.ringbuf, getpagesize());
+ bpf_map__set_max_entries(skel->maps.perfbuf, nr_cpus);
+ if (!ASSERT_OK(bpftool_ringbuf__load(skel), "load") ||
+ !consumer_start(&child, bpf_map__fd(skel->maps.perfbuf), NULL,
+ NULL, NULL, false, false) || !consumer_ready(&child) ||
+ !emit_record(skel, 3))
+ goto out;
+ /* One large record flushes the existing buffered perf output callback. */
+ pfd = (struct pollfd) { .fd = child.fd, .events = POLLIN };
+ if (!ASSERT_GT(poll(&pfd, 1, WAIT_STEPS * WAIT_US / 1000), 0,
+ "perf record output") ||
+ !ASSERT_TRUE(pfd.revents & POLLIN, "perf output readable") ||
+ !consumer_finish(&child, SIGINT, true, output, sizeof(output)))
+ goto out;
+ fields = sscanf(output, "== @%llu.%llu CPU: %d index: %d =====\n%n",
+ &seconds, &nanoseconds, &cpu, &index, &offset);
+ if (!ASSERT_EQ(fields, 4, "perf header") ||
+ !ASSERT_GT(offset, 0, "perf payload offset"))
+ goto out;
+ ASSERT_GT(seconds * 1000000000ULL + nanoseconds, 0, "perf timestamp");
+ ASSERT_LT(nanoseconds, 1000000000ULL, "perf timestamp nanoseconds");
+ ASSERT_GE(cpu, 0, "perf cpu");
+ ASSERT_LT(cpu, nr_cpus, "perf cpu range");
+ ASSERT_EQ(index, cpu, "perf index");
+ for (i = 0; i < sizeof(skel->rodata->perf_payload); i++) {
+ const char *separator = !i ? "" : !(i % 16) ? "\n" :
+ !(i % 8) ? " " : " ";
+
+ used += snprintf(expected + used, sizeof(expected) - used,
+ "%s%02x", separator, i == 1 ? 0xff : 0);
+ }
+ snprintf(expected + used, sizeof(expected) - used, "\n");
+ ASSERT_STREQ(output + offset, expected, "perf payload");
+out:
+ consumer_cleanup(&child);
+ bpftool_ringbuf__destroy(skel);
+}
+
+static void test_reject(enum bpf_map_type type, const char *option, bool pair, bool json)
+{
+ struct consumer child = { .pid = -1, .fd = -1 };
+ bool ring = type == BPF_MAP_TYPE_RINGBUF || type == BPF_MAP_TYPE_USER_RINGBUF;
+ const char *expected = option ?
+ "{\"error\":\"ring buffer maps do not support cpu or index arguments\"}" :
+ "{\"error\":\"map is not a perf event array or ring buffer\"}";
+ char output[4096];
+ int fd;
+
+ fd = bpf_map_create(type, NULL, ring ? 0 : 4, ring ? 0 : 4,
+ ring ? getpagesize() : 1, NULL);
+ if (!ASSERT_GE(fd, 0, "create map"))
+ return;
+ if (consumer_start(&child, fd, json ? "-j" : NULL, NULL, option, pair, true) &&
+ consumer_finish(&child, 0, false, output, sizeof(output))) {
+ if (json)
+ check_json(output, expected);
+ else
+ ASSERT_GT(strlen(output), 0, "error diagnostic");
+ }
+ consumer_cleanup(&child);
+ close(fd);
+}
+
+void test_bpftool_ringbuf(void)
+{
+ if (test__start_subtest("perf_event_array"))
+ test_perf_consumer();
+ if (test__start_subtest("plain"))
+ test_consumer(NULL, false, SIGINT, false);
+ if (test__start_subtest("json"))
+ test_consumer("-j", false, SIGTERM, false);
+ if (test__start_subtest("pretty_json"))
+ test_consumer("-p", false, SIGINT, false);
+ if (test__start_subtest("pinned_plain"))
+ test_consumer(NULL, false, SIGTERM, true);
+ if (test__start_subtest("pinned_json"))
+ test_consumer("-j", false, SIGINT, true);
+ if (test__start_subtest("pinned_pretty_json"))
+ test_consumer("-p", false, SIGTERM, true);
+ if (test__start_subtest("idle_sigint"))
+ test_consumer(NULL, true, SIGINT, false);
+ if (test__start_subtest("idle_sigterm_json"))
+ test_consumer("-j", true, SIGTERM, false);
+ if (test__start_subtest("idle_sigint_pretty_json"))
+ test_consumer("-p", true, SIGINT, false);
+ if (test__start_subtest("reject_array"))
+ test_reject(BPF_MAP_TYPE_ARRAY, NULL, false, false);
+ if (test__start_subtest("reject_user_ringbuf"))
+ test_reject(BPF_MAP_TYPE_USER_RINGBUF, NULL, false, false);
+ if (test__start_subtest("reject_cpu"))
+ test_reject(BPF_MAP_TYPE_RINGBUF, "cpu", false, false);
+ if (test__start_subtest("reject_index"))
+ test_reject(BPF_MAP_TYPE_RINGBUF, "index", false, false);
+ if (test__start_subtest("reject_cpu_index"))
+ test_reject(BPF_MAP_TYPE_RINGBUF, "cpu", true, false);
+ if (test__start_subtest("reject_user_ringbuf_json"))
+ test_reject(BPF_MAP_TYPE_USER_RINGBUF, NULL, false, true);
+ if (test__start_subtest("reject_cpu_index_json"))
+ test_reject(BPF_MAP_TYPE_RINGBUF, "cpu", true, true);
+}
diff --git a/tools/testing/selftests/bpf/progs/bpftool_ringbuf.c b/tools/testing/selftests/bpf/progs/bpftool_ringbuf.c
new file mode 100644
index 0000000000000..bbbc93c30a833
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bpftool_ringbuf.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+
+struct {
+ __uint(type, BPF_MAP_TYPE_RINGBUF);
+} ringbuf SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+ __uint(key_size, sizeof(__u32));
+ __uint(value_size, sizeof(__u32));
+ __uint(max_entries, 1);
+} perfbuf SEC(".maps");
+
+/*
+ * Include the u32 raw size in perf's 8-byte alignment to avoid padding.
+ * Keep plain output large enough to flush stdio before the consumer exits.
+ */
+const unsigned char perf_payload[4092] = { 0x00, 0xff };
+
+int record;
+int output_err;
+
+SEC("socket")
+int produce(struct __sk_buff *skb)
+{
+ unsigned char first[] = { 0x00, 0xff };
+ unsigned char second[] = { 1, 2, 3, 4, 5 };
+ unsigned char third[] = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ };
+
+ if (record == 0)
+ output_err = bpf_ringbuf_output(&ringbuf, first, sizeof(first), 0);
+ else if (record == 1)
+ output_err = bpf_ringbuf_output(&ringbuf, second, sizeof(second), 0);
+ else if (record == 2)
+ output_err = bpf_ringbuf_output(&ringbuf, third, sizeof(third), 0);
+ else
+ output_err = bpf_perf_event_output(skb, &perfbuf, BPF_F_CURRENT_CPU,
+ (void *)perf_payload, sizeof(perf_payload));
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
|
| 3/2 | 2026/09/11 03:00 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 11907 output: 20 thoughts: 373 Thoughts: **My Assessment of the Patch Series** Okay, so the user wants me to evaluate this patch series committed at HEAD. My first step is to quickly analyze the changed files using the provided `git diff`. I see it touches these files: `tools/bpf/bpftool/Documentation/bpftool-map.rst`, `tools/bpf/bpftool/bash-completion/bpftool`, `tools/bpf/bpftool/map_perf_ring.c`, `tools/testing/selftests/bpf/prog_tests/bpftool_ringbuf.c`, and `tools/testing/selftests/bpf/progs/bpftool_ringbuf.c`. Now, according to the guidelines, I need to determine if this warrants further fuzzing. I need to make sure this doesn't fall into the "Negative Criteria". Specifically, is *all* the modified code strictly confined to: documentation, comments, spelling fixes, user-space directories, self-tests, samples, or scripts that *don't* impact the compiled kernel image (vmlinux) or kernel modules? Based on the files listed, all modifications are within the `tools/bpf/bpftool/` and `tools/testing/selftests/bpf/` directories. This *should* mean we're dealing with user-space tools and self-tests. I need to be absolutely certain though. Even though the provided diff looks complete, I'll quickly double-check that by calling `grepper` or check the `git status` or `git diff` again. Just to make sure there are no other changes lurking that I'm missing. But based on this quick scan, this *strongly* points to the patch being safe to skip. |
| 4/2 | 2026/09/11 03:00 | tool | grepper |
0mArgs:{
"Expression": "print_ringbuf_output"
}Results: {
"Output": "tools/bpf/bpftool/map_perf_ring.c=57=print_bpf_output(void *private_data, int cpu, struct perf_event_header *event)\n--\ntools/bpf/bpftool/map_perf_ring.c-108-\ntools/bpf/bpftool/map_perf_ring.c:109:static int print_ringbuf_output(void *ctx, void *data, size_t size)\ntools/bpf/bpftool/map_perf_ring.c-110-{\n--\ntools/bpf/bpftool/map_perf_ring.c=130=int do_event_pipe(int argc, char **argv)\n--\ntools/bpf/bpftool/map_perf_ring.c-215-\tif (map_info.type == BPF_MAP_TYPE_RINGBUF) {\ntools/bpf/bpftool/map_perf_ring.c:216:\t\trb = ring_buffer__new(map_fd, print_ringbuf_output, NULL, NULL);\ntools/bpf/bpftool/map_perf_ring.c-217-\t\tif (!rb) {\n"
} |
| 5/2 | 2026/09/11 03:00 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 12986 output: 90 thoughts: 191 Thoughts: **My Assessment of the Patch's Impact** Okay, so I've taken a look at this patch and, based on the file paths, it's pretty clear where the changes lie. Everything's neatly tucked under the `tools/` directory. Section 2 of the documentation explicitly states that anything in that space, like user-space utilities, tests, or scripts, that doesn't mess with the compiled kernel image (`vmlinux`) or kernel modules, isn't something we need to fuzz. Therefore, `WorthFuzzing` is definitely set to `false` here. The `EnableConfigs` and `FocusSymbols` lists are both empty, as expected. The reasoning given – that the patch only affects user-space tools like `bpftool` and some BPF selftests – and that nothing in the kernel space itself is touched – fully supports this assessment. I've also performed a sanity check on the tool parameters, just to be thorough. The `EnableConfigs`, `FocusSymbols` and the `WorthFuzzing` are consistent, again, reinforcing my previous assessment. Looks like it's safe to call `set-results`. |
| 6/2 | 2026/09/11 03:00 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The changes are strictly limited to user-space utilities (bpftool under tools/bpf/bpftool/) and selftests (tools/testing/selftests/bpf/). No kernel-space code or compiled kernel image (vmlinux/modules) is modified.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The changes are strictly limited to user-space utilities (bpftool under tools/bpf/bpftool/) and selftests (tools/testing/selftests/bpf/). No kernel-space code or compiled kernel image (vmlinux/modules) is modified.",
"WorthFuzzing": false
} |
| 7/1 | 2026/09/11 03:00 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|