AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/20 18:20 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch only modifies BPF selftests in tools/testing/selftests/bpf/ by migrating an existing test to the test_progs framework. It does not make any functional changes to the kernel code itself.",
  "WorthFuzzing": false
}

1/1 2026/08/20 18:20 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 708042719b1559e2599ad48cb482079124e8b3c9\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Thu Aug 20 18:20:20 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile\nindex 2b2f93dec474b..f8ec0f574559a 100644\n--- a/tools/testing/selftests/bpf/Makefile\n+++ b/tools/testing/selftests/bpf/Makefile\n@@ -123,7 +123,6 @@ TEST_FILES = xsk_prereqs.sh $(wildcard progs/btf_dump_test_case_*.c)\n \n # Order correspond to 'make run_tests' order\n TEST_PROGS := test_kmod.sh \\\n-\ttest_lirc_mode2.sh \\\n \ttest_bpftool_build.sh \\\n \ttest_doc_build.sh \\\n \ttest_xsk.sh \\\n@@ -141,7 +140,6 @@ TEST_GEN_PROGS_EXTENDED = \\\n \tbench \\\n \tflow_dissector_load \\\n \ttest_cpp \\\n-\ttest_lirc_mode2_user \\\n \tveristat \\\n \txdp_features \\\n \txdp_hw_metadata \\\n@@ -338,7 +336,6 @@ $(OUTPUT)/test_sockmap: $(CGROUP_HELPERS) $(TESTING_HELPERS)\n $(OUTPUT)/test_tcpnotify_user: $(CGROUP_HELPERS) $(TESTING_HELPERS) $(TRACE_HELPERS)\n $(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)\n $(OUTPUT)/test_tag: $(TESTING_HELPERS)\n-$(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)\n $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)\n $(OUTPUT)/test_maps: $(TESTING_HELPERS)\n $(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)\ndiff --git a/tools/testing/selftests/bpf/prog_tests/lirc_mode2.c b/tools/testing/selftests/bpf/prog_tests/lirc_mode2.c\nnew file mode 100644\nindex 0000000000000..17a38cd03845c\n--- /dev/null\n+++ b/tools/testing/selftests/bpf/prog_tests/lirc_mode2.c\n@@ -0,0 +1,328 @@\n+// SPDX-License-Identifier: GPL-2.0\n+// test ir decoder\n+//\n+// Copyright (C) 2018 Sean Young \u003csean@mess.org\u003e\n+\n+// A lirc chardev is a device representing a consumer IR (cir) device which\n+// can receive infrared signals from remote control and/or transmit IR.\n+//\n+// IR is sent as a series of pulses and space somewhat like morse code. The\n+// BPF program can decode this into scancodes so that rc-core can translate\n+// this into input key codes using the rc keymap.\n+//\n+// This test works by sending IR over rc-loopback, so the IR is processed by\n+// BPF and then decoded into scancodes. The lirc chardev must be the one\n+// associated with rc-loopback, see the output of ir-keytable(1).\n+//\n+// The following CONFIG options must be enabled for the test to succeed:\n+// CONFIG_RC_CORE=y\n+// CONFIG_BPF_RAWIR_EVENT=y\n+// CONFIG_RC_LOOPBACK=y\n+\n+#include \u003clinux/input.h\u003e\n+#include \u003clinux/lirc.h\u003e\n+#include \u003cglob.h\u003e\n+#include \u003climits.h\u003e\n+#include \u003cpoll.h\u003e\n+#include \u003ctest_progs.h\u003e\n+#include \"lirc_mode2.skel.h\"\n+\n+/* Read the DEVNAME= line out of the first uevent file that matches\n+ * pattern, and turn it into a /dev/\u003cname\u003e path.\n+ */\n+static bool find_devname(const char *pattern, char *path, size_t path_sz)\n+{\n+\tglob_t gl = {};\n+\tbool found = false;\n+\tFILE *f;\n+\n+\tif (glob(pattern, 0, NULL, \u0026gl) || gl.gl_pathc == 0)\n+\t\tgoto out;\n+\n+\tf = fopen(gl.gl_pathv[0], \"r\");\n+\tif (!f)\n+\t\tgoto out;\n+\n+\tchar line[256];\n+\n+\twhile (fgets(line, sizeof(line), f)) {\n+\t\tchar *val;\n+\n+\t\tif (strncmp(line, \"DEVNAME=\", 8))\n+\t\t\tcontinue;\n+\n+\t\tval = line + 8;\n+\t\tval[strcspn(val, \"\\n\")] = '\\0';\n+\t\tsnprintf(path, path_sz, \"/dev/%s\", val);\n+\t\tfound = true;\n+\t\tbreak;\n+\t}\n+\n+\tfclose(f);\n+out:\n+\tglobfree(\u0026gl);\n+\treturn found;\n+}\n+\n+/* Load rc-loopback and find the lirc and input chardevs it created. */\n+static bool find_loopback_devices(char *lirc_path, char *input_path,\n+\t\t\t\t  size_t path_sz)\n+{\n+\tglob_t gl = {};\n+\tbool found = false;\n+\n+\t/* Ignore failure, we check for the resulting devices below. */\n+\tsystem(\"modprobe rc-loopback \u003e /dev/null 2\u003e\u00261\");\n+\n+\tif (glob(\"/sys/class/rc/rc*\", 0, NULL, \u0026gl)) {\n+\t\tfprintf(stderr, \"No rc devices found, is CONFIG_RC_LOOPBACK enabled?\\n\");\n+\t\treturn false;\n+\t}\n+\n+\tfor (size_t i = 0; i \u003c gl.gl_pathc; i++) {\n+\t\tconst char *rcdir = gl.gl_pathv[i];\n+\t\tchar uevent_path[PATH_MAX];\n+\t\tchar uevent[4096];\n+\t\tchar pattern[PATH_MAX];\n+\t\tFILE *f;\n+\t\tsize_t n;\n+\n+\t\tsnprintf(uevent_path, sizeof(uevent_path), \"%s/uevent\", rcdir);\n+\t\tf = fopen(uevent_path, \"r\");\n+\t\tif (!f)\n+\t\t\tcontinue;\n+\t\tn = fread(uevent, 1, sizeof(uevent) - 1, f);\n+\t\tfclose(f);\n+\t\tuevent[n] = '\\0';\n+\n+\t\tif (!strstr(uevent, \"DRV_NAME=rc-loopback\"))\n+\t\t\tcontinue;\n+\n+\t\tsnprintf(pattern, sizeof(pattern), \"%s/lirc*/uevent\", rcdir);\n+\t\tif (!find_devname(pattern, lirc_path, path_sz))\n+\t\t\tcontinue;\n+\n+\t\tsnprintf(pattern, sizeof(pattern), \"%s/input*/event*/uevent\", rcdir);\n+\t\tif (!find_devname(pattern, input_path, path_sz))\n+\t\t\tcontinue;\n+\n+\t\tfound = true;\n+\t\tbreak;\n+\t}\n+\n+\tglobfree(\u0026gl);\n+\treturn found;\n+}\n+\n+void test_lirc_mode2(void)\n+{\n+\tchar lirc_path[PATH_MAX], input_path[PATH_MAX];\n+\tint lircfd = -1, inputfd = -1, progfd, progfd2 = -1;\n+\tstruct lirc_mode2 *skel = NULL, *skel2 = NULL;\n+\t__u32 prog_ids[10], prog_flags[10], prog_cnt;\n+\tstruct bpf_prog_info info;\n+\t__u32 info_len, prog_id, prog_id2;\n+\tint testir1 = 0x8ead;\t/* keydown flag (0x8000) | scancode 0xead */\n+\tint testir2 = 0x4081;\t/* pointer_rel flag (0x4000) | rel_x=1 | rel_y=1 */\n+\tstruct input_event event;\n+\tstruct pollfd pfd = {};\n+\tint ret;\n+\n+\tif (getuid() != 0) {\n+\t\ttest__skip();\n+\t\treturn;\n+\t}\n+\n+\tif (!find_loopback_devices(lirc_path, input_path, sizeof(lirc_path))) {\n+\t\ttest__skip();\n+\t\treturn;\n+\t}\n+\n+\tskel = lirc_mode2__open_and_load();\n+\tif (!ASSERT_OK_PTR(skel, \"lirc_mode2__open_and_load\"))\n+\t\treturn;\n+\n+\tprogfd = bpf_program__fd(skel-\u003eprogs.bpf_decoder);\n+\n+\tmemset(\u0026info, 0, sizeof(info));\n+\tinfo_len = sizeof(info);\n+\tret = bpf_prog_get_info_by_fd(progfd, \u0026info, \u0026info_len);\n+\tif (!ASSERT_OK(ret, \"get first program's info\"))\n+\t\tgoto out;\n+\tprog_id = info.id;\n+\n+\tlircfd = open(lirc_path, O_RDWR | O_NONBLOCK);\n+\tif (!ASSERT_GE(lircfd, 0, \"open lirc device\"))\n+\t\tgoto out;\n+\n+\t/* Try to detach it before it was ever attached, should fail. */\n+\tret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);\n+\tif (!ASSERT_EQ(ret, -ENOENT, \"detach unattached program\"))\n+\t\tgoto out;\n+\n+\tinputfd = open(input_path, O_RDONLY | O_NONBLOCK);\n+\tif (!ASSERT_GE(inputfd, 0, \"open input device\"))\n+\t\tgoto out;\n+\n+\tprog_cnt = ARRAY_SIZE(prog_ids);\n+\tret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,\n+\t\t\t     \u0026prog_cnt);\n+\tif (!ASSERT_OK(ret, \"query programs before attach\"))\n+\t\tgoto out;\n+\tif (!ASSERT_EQ(prog_cnt, 0, \"no programs should be attached yet\"))\n+\t\tgoto out;\n+\n+\t/* Invalid attach flags must be rejected, and must not attach. */\n+\tret = bpf_prog_attach(progfd, lircfd, BPF_LIRC_MODE2, 1);\n+\tif (!ASSERT_EQ(ret, -EINVAL, \"attach with invalid flags\"))\n+\t\tgoto out;\n+\n+\tprog_cnt = ARRAY_SIZE(prog_ids);\n+\tret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,\n+\t\t\t     \u0026prog_cnt);\n+\tif (!ASSERT_OK(ret, \"query programs after rejected attach\"))\n+\t\tgoto out;\n+\tif (!ASSERT_EQ(prog_cnt, 0, \"rejected attach should not attach\"))\n+\t\tgoto out;\n+\n+\tret = bpf_prog_attach(progfd, lircfd, BPF_LIRC_MODE2, 0);\n+\tif (!ASSERT_OK(ret, \"attach program to lirc device\"))\n+\t\tgoto out;\n+\n+\t/* Invalid query flags must be rejected too, without upsetting state. */\n+\tprog_cnt = ARRAY_SIZE(prog_ids);\n+\tret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 1, prog_flags, prog_ids,\n+\t\t\t     \u0026prog_cnt);\n+\tASSERT_EQ(ret, -EINVAL, \"query with invalid flags\");\n+\n+\tprog_cnt = ARRAY_SIZE(prog_ids);\n+\tret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,\n+\t\t\t     \u0026prog_cnt);\n+\tif (!ASSERT_OK(ret, \"query programs after attach\"))\n+\t\tgoto out_detach;\n+\tif (!ASSERT_EQ(prog_cnt, 1, \"one program should be attached\"))\n+\t\tgoto out_detach;\n+\tASSERT_EQ(prog_ids[0], prog_id, \"queried id should match attached program\");\n+\n+\t/* Write raw IR */\n+\tret = write(lircfd, \u0026testir1, sizeof(testir1));\n+\tif (!ASSERT_EQ(ret, sizeof(testir1), \"send test IR message 1\"))\n+\t\tgoto out_detach;\n+\n+\tpfd.fd = inputfd;\n+\tpfd.events = POLLIN;\n+\n+\tfor (;;) {\n+\t\tpoll(\u0026pfd, 1, 100);\n+\n+\t\t/* Read decoded IR */\n+\t\tret = read(inputfd, \u0026event, sizeof(event));\n+\t\tif (!ASSERT_EQ(ret, sizeof(event), \"read decoded IR 1\"))\n+\t\t\tgoto out_detach;\n+\n+\t\tif (event.type == EV_MSC \u0026\u0026 event.code == MSC_SCAN \u0026\u0026\n+\t\t    event.value == 0xead)\n+\t\t\tbreak;\n+\t}\n+\n+\t/* Write raw IR */\n+\tret = write(lircfd, \u0026testir2, sizeof(testir2));\n+\tif (!ASSERT_EQ(ret, sizeof(testir2), \"send test IR message 2\"))\n+\t\tgoto out_detach;\n+\n+\tfor (;;) {\n+\t\tpoll(\u0026pfd, 1, 100);\n+\n+\t\t/* Read decoded IR */\n+\t\tret = read(inputfd, \u0026event, sizeof(event));\n+\t\tif (!ASSERT_EQ(ret, sizeof(event), \"read decoded IR 2\"))\n+\t\t\tgoto out_detach;\n+\n+\t\tif (event.type == EV_REL \u0026\u0026 event.code == REL_Y \u0026\u0026\n+\t\t    event.value == 1)\n+\t\t\tbreak;\n+\t}\n+\n+\tprog_cnt = ARRAY_SIZE(prog_ids);\n+\tret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,\n+\t\t\t     \u0026prog_cnt);\n+\tif (!ASSERT_OK(ret, \"query programs after IR was decoded\"))\n+\t\tgoto out_detach;\n+\tif (!ASSERT_EQ(prog_cnt, 1, \"one program should still be attached\"))\n+\t\tgoto out_detach;\n+\n+\t/*\n+\t * The lirc chardev can hold more than one attached program at once.\n+\t * Load a second, independent instance and check it can be attached\n+\t * alongside the first, queried, and then detached on its own\n+\t * without disturbing the first program's attachment.\n+\t */\n+\tskel2 = lirc_mode2__open_and_load();\n+\tif (!ASSERT_OK_PTR(skel2, \"lirc_mode2__open_and_load (2nd)\"))\n+\t\tgoto out_detach;\n+\n+\tprogfd2 = bpf_program__fd(skel2-\u003eprogs.bpf_decoder);\n+\n+\tmemset(\u0026info, 0, sizeof(info));\n+\tinfo_len = sizeof(info);\n+\tret = bpf_prog_get_info_by_fd(progfd2, \u0026info, \u0026info_len);\n+\tif (!ASSERT_OK(ret, \"get second program's info\"))\n+\t\tgoto out_detach;\n+\tprog_id2 = info.id;\n+\n+\tret = bpf_prog_attach(progfd2, lircfd, BPF_LIRC_MODE2, 0);\n+\tif (!ASSERT_OK(ret, \"attach second program to lirc device\"))\n+\t\tgoto out_detach;\n+\n+\tprog_cnt = ARRAY_SIZE(prog_ids);\n+\tret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,\n+\t\t\t     \u0026prog_cnt);\n+\tif (!ASSERT_OK(ret, \"query programs after second attach\"))\n+\t\tgoto out_detach2;\n+\tif (!ASSERT_EQ(prog_cnt, 2, \"two programs should be attached\"))\n+\t\tgoto out_detach2;\n+\tASSERT_TRUE((prog_ids[0] == prog_id \u0026\u0026 prog_ids[1] == prog_id2) ||\n+\t\t    (prog_ids[0] == prog_id2 \u0026\u0026 prog_ids[1] == prog_id),\n+\t\t    \"queried ids should be the two attached programs\");\n+\n+\t/* Detach the second program; the first should remain attached. */\n+\tret = bpf_prog_detach2(progfd2, lircfd, BPF_LIRC_MODE2);\n+\tif (!ASSERT_OK(ret, \"detach second program\"))\n+\t\tgoto out_detach2;\n+\n+\t/* Detaching an already-detached program should now fail. */\n+\tret = bpf_prog_detach2(progfd2, lircfd, BPF_LIRC_MODE2);\n+\tASSERT_EQ(ret, -ENOENT, \"detach second program again\");\n+\n+\tprog_cnt = ARRAY_SIZE(prog_ids);\n+\tret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,\n+\t\t\t     \u0026prog_cnt);\n+\tif (!ASSERT_OK(ret, \"query programs after second detach\"))\n+\t\tgoto out_detach;\n+\tif (!ASSERT_EQ(prog_cnt, 1, \"one program should remain attached\"))\n+\t\tgoto out_detach;\n+\tASSERT_EQ(prog_ids[0], prog_id, \"remaining program should be the first one\");\n+\n+out_detach:\n+\t/* Let's try detaching it now it is actually attached. */\n+\tret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);\n+\tASSERT_OK(ret, \"detach program from lirc device\");\n+\n+\t/* Detaching it again should now fail the same way. */\n+\tret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);\n+\tASSERT_EQ(ret, -ENOENT, \"detach program from lirc device again\");\n+\tgoto out;\n+\n+out_detach2:\n+\t/* Best-effort cleanup of the second program before bailing out. */\n+\tbpf_prog_detach2(progfd2, lircfd, BPF_LIRC_MODE2);\n+\tgoto out_detach;\n+\n+out:\n+\tif (inputfd \u003e= 0)\n+\t\tclose(inputfd);\n+\tif (lircfd \u003e= 0)\n+\t\tclose(lircfd);\n+\tlirc_mode2__destroy(skel2);\n+\tlirc_mode2__destroy(skel);\n+}\ndiff --git a/tools/testing/selftests/bpf/progs/lirc_mode2.c b/tools/testing/selftests/bpf/progs/lirc_mode2.c\nnew file mode 100644\nindex 0000000000000..98137f3c5c03d\n--- /dev/null\n+++ b/tools/testing/selftests/bpf/progs/lirc_mode2.c\n@@ -0,0 +1,32 @@\n+// SPDX-License-Identifier: GPL-2.0\n+// test ir decoder\n+//\n+// Copyright (C) 2018 Sean Young \u003csean@mess.org\u003e\n+\n+#include \u003clinux/bpf.h\u003e\n+#include \u003clinux/lirc.h\u003e\n+#include \u003cbpf/bpf_helpers.h\u003e\n+\n+SEC(\"lirc_mode2\")\n+int bpf_decoder(unsigned int *sample)\n+{\n+\tif (LIRC_IS_PULSE(*sample)) {\n+\t\tunsigned int duration = LIRC_VALUE(*sample);\n+\n+\t\t/*\n+\t\t * Flag bits picked deliberately low: rc-loopback simulates\n+\t\t * a receiver overflow for any pulse over MS_TO_US(50) (see\n+\t\t * loop_tx_ir() in rc-loopback.c), which would silently\n+\t\t * swallow the sample before it ever reaches this decoder.\n+\t\t */\n+\t\tif (duration \u0026 0x8000)\n+\t\t\tbpf_rc_keydown(sample, 0x40, duration \u0026 0x3fff, 0);\n+\t\tif (duration \u0026 0x4000)\n+\t\t\tbpf_rc_pointer_rel(sample, (duration \u003e\u003e 7) \u0026 0x7f,\n+\t\t\t\t\t   duration \u0026 0x7f);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+char _license[] SEC(\"license\") = \"GPL\";\ndiff --git a/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c b/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c\ndeleted file mode 100644\nindex cbe4284c032fe..0000000000000\n--- a/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c\n+++ /dev/null\n@@ -1,26 +0,0 @@\n-// SPDX-License-Identifier: GPL-2.0\n-// test ir decoder\n-//\n-// Copyright (C) 2018 Sean Young \u003csean@mess.org\u003e\n-\n-#include \u003clinux/bpf.h\u003e\n-#include \u003clinux/lirc.h\u003e\n-#include \u003cbpf/bpf_helpers.h\u003e\n-\n-SEC(\"lirc_mode2\")\n-int bpf_decoder(unsigned int *sample)\n-{\n-\tif (LIRC_IS_PULSE(*sample)) {\n-\t\tunsigned int duration = LIRC_VALUE(*sample);\n-\n-\t\tif (duration \u0026 0x1000)\n-\t\t\tbpf_rc_keydown(sample, 0x40, duration \u0026 0xffff, 0);\n-\t\tif (duration \u0026 0x2000)\n-\t\t\tbpf_rc_pointer_rel(sample, (duration \u003e\u003e 8) \u0026 0xff,\n-\t\t\t\t\t   duration \u0026 0xff);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-char _license[] SEC(\"license\") = \"GPL\";\ndiff --git a/tools/testing/selftests/bpf/test_lirc_mode2.sh b/tools/testing/selftests/bpf/test_lirc_mode2.sh\ndeleted file mode 100755\nindex 5252b91f48a18..0000000000000\n--- a/tools/testing/selftests/bpf/test_lirc_mode2.sh\n+++ /dev/null\n@@ -1,41 +0,0 @@\n-#!/bin/bash\n-# SPDX-License-Identifier: GPL-2.0\n-\n-# Kselftest framework requirement - SKIP code is 4.\n-ksft_skip=4\n-ret=$ksft_skip\n-\n-msg=\"skip all tests:\"\n-if [ $UID != 0 ]; then\n-\techo $msg please run this as root \u003e\u00262\n-\texit $ksft_skip\n-fi\n-\n-GREEN='\\033[0;92m'\n-RED='\\033[0;31m'\n-NC='\\033[0m' # No Color\n-\n-modprobe rc-loopback\n-\n-for i in /sys/class/rc/rc*\n-do\n-\tif grep -q DRV_NAME=rc-loopback $i/uevent\n-\tthen\n-\t\tLIRCDEV=$(grep DEVNAME= $i/lirc*/uevent | sed sQDEVNAME=Q/dev/Q)\n-\t\tINPUTDEV=$(grep DEVNAME= $i/input*/event*/uevent | sed sQDEVNAME=Q/dev/Q)\n-\tfi\n-done\n-\n-if [ -n \"$LIRCDEV\" ];\n-then\n-\tTYPE=lirc_mode2\n-\t./test_lirc_mode2_user $LIRCDEV $INPUTDEV\n-\tret=$?\n-\tif [ $ret -ne 0 ]; then\n-\t\techo -e ${RED}\"FAIL: $TYPE\"${NC}\n-\telse\n-\t\techo -e ${GREEN}\"PASS: $TYPE\"${NC}\n-\tfi\n-fi\n-\n-exit $ret\n"
}

2/1 2026/08/20 18:20 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies BPF selftests in tools/testing/selftests/bpf/ by migrating an existing test to the test_progs framework. It does not make any functional changes to the kernel code itself.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
  even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs
   output array, and DO NOT add a '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:
For your convenience, here is the diff of the changes:
commit 708042719b1559e2599ad48cb482079124e8b3c9
Author: syz-cluster <triage@syzkaller.com>
Date:   Thu Aug 20 18:20:20 2026 +0000

    syz-cluster: applied patch under review

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 2b2f93dec474b..f8ec0f574559a 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -123,7 +123,6 @@ TEST_FILES = xsk_prereqs.sh $(wildcard progs/btf_dump_test_case_*.c)
 
 # Order correspond to 'make run_tests' order
 TEST_PROGS := test_kmod.sh \
-	test_lirc_mode2.sh \
 	test_bpftool_build.sh \
 	test_doc_build.sh \
 	test_xsk.sh \
@@ -141,7 +140,6 @@ TEST_GEN_PROGS_EXTENDED = \
 	bench \
 	flow_dissector_load \
 	test_cpp \
-	test_lirc_mode2_user \
 	veristat \
 	xdp_features \
 	xdp_hw_metadata \
@@ -338,7 +336,6 @@ $(OUTPUT)/test_sockmap: $(CGROUP_HELPERS) $(TESTING_HELPERS)
 $(OUTPUT)/test_tcpnotify_user: $(CGROUP_HELPERS) $(TESTING_HELPERS) $(TRACE_HELPERS)
 $(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)
 $(OUTPUT)/test_tag: $(TESTING_HELPERS)
-$(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
 $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
 $(OUTPUT)/test_maps: $(TESTING_HELPERS)
 $(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)
diff --git a/tools/testing/selftests/bpf/prog_tests/lirc_mode2.c b/tools/testing/selftests/bpf/prog_tests/lirc_mode2.c
new file mode 100644
index 0000000000000..17a38cd03845c
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/lirc_mode2.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0
+// test ir decoder
+//
+// Copyright (C) 2018 Sean Young <sean@mess.org>
+
+// A lirc chardev is a device representing a consumer IR (cir) device which
+// can receive infrared signals from remote control and/or transmit IR.
+//
+// IR is sent as a series of pulses and space somewhat like morse code. The
+// BPF program can decode this into scancodes so that rc-core can translate
+// this into input key codes using the rc keymap.
+//
+// This test works by sending IR over rc-loopback, so the IR is processed by
+// BPF and then decoded into scancodes. The lirc chardev must be the one
+// associated with rc-loopback, see the output of ir-keytable(1).
+//
+// The following CONFIG options must be enabled for the test to succeed:
+// CONFIG_RC_CORE=y
+// CONFIG_BPF_RAWIR_EVENT=y
+// CONFIG_RC_LOOPBACK=y
+
+#include <linux/input.h>
+#include <linux/lirc.h>
+#include <glob.h>
+#include <limits.h>
+#include <poll.h>
+#include <test_progs.h>
+#include "lirc_mode2.skel.h"
+
+/* Read the DEVNAME= line out of the first uevent file that matches
+ * pattern, and turn it into a /dev/<name> path.
+ */
+static bool find_devname(const char *pattern, char *path, size_t path_sz)
+{
+	glob_t gl = {};
+	bool found = false;
+	FILE *f;
+
+	if (glob(pattern, 0, NULL, &gl) || gl.gl_pathc == 0)
+		goto out;
+
+	f = fopen(gl.gl_pathv[0], "r");
+	if (!f)
+		goto out;
+
+	char line[256];
+
+	while (fgets(line, sizeof(line), f)) {
+		char *val;
+
+		if (strncmp(line, "DEVNAME=", 8))
+			continue;
+
+		val = line + 8;
+		val[strcspn(val, "\n")] = '\0';
+		snprintf(path, path_sz, "/dev/%s", val);
+		found = true;
+		break;
+	}
+
+	fclose(f);
+out:
+	globfree(&gl);
+	return found;
+}
+
+/* Load rc-loopback and find the lirc and input chardevs it created. */
+static bool find_loopback_devices(char *lirc_path, char *input_path,
+				  size_t path_sz)
+{
+	glob_t gl = {};
+	bool found = false;
+
+	/* Ignore failure, we check for the resulting devices below. */
+	system("modprobe rc-loopback > /dev/null 2>&1");
+
+	if (glob("/sys/class/rc/rc*", 0, NULL, &gl)) {
+		fprintf(stderr, "No rc devices found, is CONFIG_RC_LOOPBACK enabled?\n");
+		return false;
+	}
+
+	for (size_t i = 0; i < gl.gl_pathc; i++) {
+		const char *rcdir = gl.gl_pathv[i];
+		char uevent_path[PATH_MAX];
+		char uevent[4096];
+		char pattern[PATH_MAX];
+		FILE *f;
+		size_t n;
+
+		snprintf(uevent_path, sizeof(uevent_path), "%s/uevent", rcdir);
+		f = fopen(uevent_path, "r");
+		if (!f)
+			continue;
+		n = fread(uevent, 1, sizeof(uevent) - 1, f);
+		fclose(f);
+		uevent[n] = '\0';
+
+		if (!strstr(uevent, "DRV_NAME=rc-loopback"))
+			continue;
+
+		snprintf(pattern, sizeof(pattern), "%s/lirc*/uevent", rcdir);
+		if (!find_devname(pattern, lirc_path, path_sz))
+			continue;
+
+		snprintf(pattern, sizeof(pattern), "%s/input*/event*/uevent", rcdir);
+		if (!find_devname(pattern, input_path, path_sz))
+			continue;
+
+		found = true;
+		break;
+	}
+
+	globfree(&gl);
+	return found;
+}
+
+void test_lirc_mode2(void)
+{
+	char lirc_path[PATH_MAX], input_path[PATH_MAX];
+	int lircfd = -1, inputfd = -1, progfd, progfd2 = -1;
+	struct lirc_mode2 *skel = NULL, *skel2 = NULL;
+	__u32 prog_ids[10], prog_flags[10], prog_cnt;
+	struct bpf_prog_info info;
+	__u32 info_len, prog_id, prog_id2;
+	int testir1 = 0x8ead;	/* keydown flag (0x8000) | scancode 0xead */
+	int testir2 = 0x4081;	/* pointer_rel flag (0x4000) | rel_x=1 | rel_y=1 */
+	struct input_event event;
+	struct pollfd pfd = {};
+	int ret;
+
+	if (getuid() != 0) {
+		test__skip();
+		return;
+	}
+
+	if (!find_loopback_devices(lirc_path, input_path, sizeof(lirc_path))) {
+		test__skip();
+		return;
+	}
+
+	skel = lirc_mode2__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "lirc_mode2__open_and_load"))
+		return;
+
+	progfd = bpf_program__fd(skel->progs.bpf_decoder);
+
+	memset(&info, 0, sizeof(info));
+	info_len = sizeof(info);
+	ret = bpf_prog_get_info_by_fd(progfd, &info, &info_len);
+	if (!ASSERT_OK(ret, "get first program's info"))
+		goto out;
+	prog_id = info.id;
+
+	lircfd = open(lirc_path, O_RDWR | O_NONBLOCK);
+	if (!ASSERT_GE(lircfd, 0, "open lirc device"))
+		goto out;
+
+	/* Try to detach it before it was ever attached, should fail. */
+	ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
+	if (!ASSERT_EQ(ret, -ENOENT, "detach unattached program"))
+		goto out;
+
+	inputfd = open(input_path, O_RDONLY | O_NONBLOCK);
+	if (!ASSERT_GE(inputfd, 0, "open input device"))
+		goto out;
+
+	prog_cnt = ARRAY_SIZE(prog_ids);
+	ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
+			     &prog_cnt);
+	if (!ASSERT_OK(ret, "query programs before attach"))
+		goto out;
+	if (!ASSERT_EQ(prog_cnt, 0, "no programs should be attached yet"))
+		goto out;
+
+	/* Invalid attach flags must be rejected, and must not attach. */
+	ret = bpf_prog_attach(progfd, lircfd, BPF_LIRC_MODE2, 1);
+	if (!ASSERT_EQ(ret, -EINVAL, "attach with invalid flags"))
+		goto out;
+
+	prog_cnt = ARRAY_SIZE(prog_ids);
+	ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
+			     &prog_cnt);
+	if (!ASSERT_OK(ret, "query programs after rejected attach"))
+		goto out;
+	if (!ASSERT_EQ(prog_cnt, 0, "rejected attach should not attach"))
+		goto out;
+
+	ret = bpf_prog_attach(progfd, lircfd, BPF_LIRC_MODE2, 0);
+	if (!ASSERT_OK(ret, "attach program to lirc device"))
+		goto out;
+
+	/* Invalid query flags must be rejected too, without upsetting state. */
+	prog_cnt = ARRAY_SIZE(prog_ids);
+	ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 1, prog_flags, prog_ids,
+			     &prog_cnt);
+	ASSERT_EQ(ret, -EINVAL, "query with invalid flags");
+
+	prog_cnt = ARRAY_SIZE(prog_ids);
+	ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
+			     &prog_cnt);
+	if (!ASSERT_OK(ret, "query programs after attach"))
+		goto out_detach;
+	if (!ASSERT_EQ(prog_cnt, 1, "one program should be attached"))
+		goto out_detach;
+	ASSERT_EQ(prog_ids[0], prog_id, "queried id should match attached program");
+
+	/* Write raw IR */
+	ret = write(lircfd, &testir1, sizeof(testir1));
+	if (!ASSERT_EQ(ret, sizeof(testir1), "send test IR message 1"))
+		goto out_detach;
+
+	pfd.fd = inputfd;
+	pfd.events = POLLIN;
+
+	for (;;) {
+		poll(&pfd, 1, 100);
+
+		/* Read decoded IR */
+		ret = read(inputfd, &event, sizeof(event));
+		if (!ASSERT_EQ(ret, sizeof(event), "read decoded IR 1"))
+			goto out_detach;
+
+		if (event.type == EV_MSC && event.code == MSC_SCAN &&
+		    event.value == 0xead)
+			break;
+	}
+
+	/* Write raw IR */
+	ret = write(lircfd, &testir2, sizeof(testir2));
+	if (!ASSERT_EQ(ret, sizeof(testir2), "send test IR message 2"))
+		goto out_detach;
+
+	for (;;) {
+		poll(&pfd, 1, 100);
+
+		/* Read decoded IR */
+		ret = read(inputfd, &event, sizeof(event));
+		if (!ASSERT_EQ(ret, sizeof(event), "read decoded IR 2"))
+			goto out_detach;
+
+		if (event.type == EV_REL && event.code == REL_Y &&
+		    event.value == 1)
+			break;
+	}
+
+	prog_cnt = ARRAY_SIZE(prog_ids);
+	ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
+			     &prog_cnt);
+	if (!ASSERT_OK(ret, "query programs after IR was decoded"))
+		goto out_detach;
+	if (!ASSERT_EQ(prog_cnt, 1, "one program should still be attached"))
+		goto out_detach;
+
+	/*
+	 * The lirc chardev can hold more than one attached program at once.
+	 * Load a second, independent instance and check it can be attached
+	 * alongside the first, queried, and then detached on its own
+	 * without disturbing the first program's attachment.
+	 */
+	skel2 = lirc_mode2__open_and_load();
+	if (!ASSERT_OK_PTR(skel2, "lirc_mode2__open_and_load (2nd)"))
+		goto out_detach;
+
+	progfd2 = bpf_program__fd(skel2->progs.bpf_decoder);
+
+	memset(&info, 0, sizeof(info));
+	info_len = sizeof(info);
+	ret = bpf_prog_get_info_by_fd(progfd2, &info, &info_len);
+	if (!ASSERT_OK(ret, "get second program's info"))
+		goto out_detach;
+	prog_id2 = info.id;
+
+	ret = bpf_prog_attach(progfd2, lircfd, BPF_LIRC_MODE2, 0);
+	if (!ASSERT_OK(ret, "attach second program to lirc device"))
+		goto out_detach;
+
+	prog_cnt = ARRAY_SIZE(prog_ids);
+	ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
+			     &prog_cnt);
+	if (!ASSERT_OK(ret, "query programs after second attach"))
+		goto out_detach2;
+	if (!ASSERT_EQ(prog_cnt, 2, "two programs should be attached"))
+		goto out_detach2;
+	ASSERT_TRUE((prog_ids[0] == prog_id && prog_ids[1] == prog_id2) ||
+		    (prog_ids[0] == prog_id2 && prog_ids[1] == prog_id),
+		    "queried ids should be the two attached programs");
+
+	/* Detach the second program; the first should remain attached. */
+	ret = bpf_prog_detach2(progfd2, lircfd, BPF_LIRC_MODE2);
+	if (!ASSERT_OK(ret, "detach second program"))
+		goto out_detach2;
+
+	/* Detaching an already-detached program should now fail. */
+	ret = bpf_prog_detach2(progfd2, lircfd, BPF_LIRC_MODE2);
+	ASSERT_EQ(ret, -ENOENT, "detach second program again");
+
+	prog_cnt = ARRAY_SIZE(prog_ids);
+	ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
+			     &prog_cnt);
+	if (!ASSERT_OK(ret, "query programs after second detach"))
+		goto out_detach;
+	if (!ASSERT_EQ(prog_cnt, 1, "one program should remain attached"))
+		goto out_detach;
+	ASSERT_EQ(prog_ids[0], prog_id, "remaining program should be the first one");
+
+out_detach:
+	/* Let's try detaching it now it is actually attached. */
+	ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
+	ASSERT_OK(ret, "detach program from lirc device");
+
+	/* Detaching it again should now fail the same way. */
+	ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
+	ASSERT_EQ(ret, -ENOENT, "detach program from lirc device again");
+	goto out;
+
+out_detach2:
+	/* Best-effort cleanup of the second program before bailing out. */
+	bpf_prog_detach2(progfd2, lircfd, BPF_LIRC_MODE2);
+	goto out_detach;
+
+out:
+	if (inputfd >= 0)
+		close(inputfd);
+	if (lircfd >= 0)
+		close(lircfd);
+	lirc_mode2__destroy(skel2);
+	lirc_mode2__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/lirc_mode2.c b/tools/testing/selftests/bpf/progs/lirc_mode2.c
new file mode 100644
index 0000000000000..98137f3c5c03d
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/lirc_mode2.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+// test ir decoder
+//
+// Copyright (C) 2018 Sean Young <sean@mess.org>
+
+#include <linux/bpf.h>
+#include <linux/lirc.h>
+#include <bpf/bpf_helpers.h>
+
+SEC("lirc_mode2")
+int bpf_decoder(unsigned int *sample)
+{
+	if (LIRC_IS_PULSE(*sample)) {
+		unsigned int duration = LIRC_VALUE(*sample);
+
+		/*
+		 * Flag bits picked deliberately low: rc-loopback simulates
+		 * a receiver overflow for any pulse over MS_TO_US(50) (see
+		 * loop_tx_ir() in rc-loopback.c), which would silently
+		 * swallow the sample before it ever reaches this decoder.
+		 */
+		if (duration & 0x8000)
+			bpf_rc_keydown(sample, 0x40, duration & 0x3fff, 0);
+		if (duration & 0x4000)
+			bpf_rc_pointer_rel(sample, (duration >> 7) & 0x7f,
+					   duration & 0x7f);
+	}
+
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c b/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c
deleted file mode 100644
index cbe4284c032fe..0000000000000
--- a/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// test ir decoder
-//
-// Copyright (C) 2018 Sean Young <sean@mess.org>
-
-#include <linux/bpf.h>
-#include <linux/lirc.h>
-#include <bpf/bpf_helpers.h>
-
-SEC("lirc_mode2")
-int bpf_decoder(unsigned int *sample)
-{
-	if (LIRC_IS_PULSE(*sample)) {
-		unsigned int duration = LIRC_VALUE(*sample);
-
-		if (duration & 0x1000)
-			bpf_rc_keydown(sample, 0x40, duration & 0xffff, 0);
-		if (duration & 0x2000)
-			bpf_rc_pointer_rel(sample, (duration >> 8) & 0xff,
-					   duration & 0xff);
-	}
-
-	return 0;
-}
-
-char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_lirc_mode2.sh b/tools/testing/selftests/bpf/test_lirc_mode2.sh
deleted file mode 100755
index 5252b91f48a18..0000000000000
--- a/tools/testing/selftests/bpf/test_lirc_mode2.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-# SPDX-License-Identifier: GPL-2.0
-
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-ret=$ksft_skip
-
-msg="skip all tests:"
-if [ $UID != 0 ]; then
-	echo $msg please run this as root >&2
-	exit $ksft_skip
-fi
-
-GREEN='\033[0;92m'
-RED='\033[0;31m'
-NC='\033[0m' # No Color
-
-modprobe rc-loopback
-
-for i in /sys/class/rc/rc*
-do
-	if grep -q DRV_NAME=rc-loopback $i/uevent
-	then
-		LIRCDEV=$(grep DEVNAME= $i/lirc*/uevent | sed sQDEVNAME=Q/dev/Q)
-		INPUTDEV=$(grep DEVNAME= $i/input*/event*/uevent | sed sQDEVNAME=Q/dev/Q)
-	fi
-done
-
-if [ -n "$LIRCDEV" ];
-then
-	TYPE=lirc_mode2
-	./test_lirc_mode2_user $LIRCDEV $INPUTDEV
-	ret=$?
-	if [ $ret -ne 0 ]; then
-		echo -e ${RED}"FAIL: $TYPE"${NC}
-	else
-		echo -e ${GREEN}"PASS: $TYPE"${NC}
-	fi
-fi
-
-exit $ret

3/2 2026/08/20 18:20 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 7888
							output: 78
							thoughts: 523
						

Thoughts:
**Analyzing the BPF Selftest Migration**

Okay, so this patch is touching `tools/testing/selftests/bpf/`. My initial impression is that it's a refactoring, specifically removing the old `test_lirc_mode2.sh`, `test_lirc_mode2_kern.c`, and `test_lirc_mode2_user.c` (oh, it also removes `test_lirc_mode2_user` from the `Makefile`), and replacing it with `prog_tests/lirc_mode2.c` and `progs/lirc_mode2.c`. Seems like a straightforward migration from the older bash/user format to the newer `test_progs` framework within the BPF selftests.

Since the scope is limited to the selftests directory, my gut feeling is that this *shouldn't* introduce any functional changes to the kernel itself. Just to be absolutely sure, I'll quickly double-check that the diff doesn't touch anything outside of that directory. Yep, confirming that the change is contained solely within `tools/testing/selftests/bpf/`. Therefore, I'm confident in setting `WorthFuzzing=false`.

I quickly went through the rules again to confirm my judgement. The rules seem to confirm the choice. Selftests are userspace tests and are not kernel code; they don't introduce kernel code that warrants fuzzing. Therefore I will set `WorthFuzzing=false`. Time to call `set-results`.



4/2 2026/08/20 18:20 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies BPF selftests in tools/testing/selftests/bpf/ by migrating an existing test to the test_progs framework. It does not make any functional changes to the kernel code itself.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies BPF selftests in tools/testing/selftests/bpf/ by migrating an existing test to the test_progs framework. It does not make any functional changes to the kernel code itself.",
  "WorthFuzzing": false
}

5/1 2026/08/20 18:20 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)