AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/06/26 15:33 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL"
  ],
  "FocusSymbols": [
    "bpf_strpbrk",
    "bpf_memcmp"
  ],
  "Reasoning": "The patch introduces two new BPF kfuncs, bpf_strpbrk and bpf_memcmp, which can be called from BPF programs. These are functional additions to the core BPF helper library and should be fuzzed.",
  "WorthFuzzing": true
}

1/1 2026/06/26 15:33 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 78fad54457c40244496e8ce00bc41cb77a6c51fb\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Fri Jun 26 15:33:56 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c\nindex b5314c9fed3cf0..ead00ec314f54a 100644\n--- a/kernel/bpf/helpers.c\n+++ b/kernel/bpf/helpers.c\n@@ -3971,6 +3971,92 @@ __bpf_kfunc int bpf_strcspn(const char *s__ign, const char *reject__ign)\n \treturn -EFAULT;\n }\n \n+/**\n+ * bpf_strpbrk - Find the first occurrence of a set of characters in a string\n+ * @s__ign: The string to be searched\n+ * @accept__ign: The string containing the characters to search for\n+ *\n+ * Return:\n+ * * \u003e=0      - Index of the first character in @s__ign that matches any\n+ *              character in @accept__ign\n+ * * %-ENOENT - No character of @accept__ign found in @s__ign\n+ * * %-EFAULT - Cannot read one of the strings\n+ * * %-E2BIG  - One of the strings is too large\n+ * * %-ERANGE - One of the strings is outside of kernel address space\n+ */\n+__bpf_kfunc int bpf_strpbrk(const char *s__ign, const char *accept__ign)\n+{\n+\tchar cs, ca;\n+\tint i, j;\n+\n+\tif (!copy_from_kernel_nofault_allowed(s__ign, 1) ||\n+\t    !copy_from_kernel_nofault_allowed(accept__ign, 1)) {\n+\t\treturn -ERANGE;\n+\t}\n+\n+\tguard(pagefault)();\n+\tfor (i = 0; i \u003c XATTR_SIZE_MAX; i++) {\n+\t\t__get_kernel_nofault(\u0026cs, s__ign, char, err_out);\n+\t\tif (cs == '\\0')\n+\t\t\treturn -ENOENT;\n+\t\tfor (j = 0; j \u003c XATTR_SIZE_MAX; j++) {\n+\t\t\t__get_kernel_nofault(\u0026ca, accept__ign + j, char, err_out);\n+\t\t\tif (ca == '\\0')\n+\t\t\t\tbreak;\n+\t\t\tif (cs == ca)\n+\t\t\t\treturn i;\n+\t\t}\n+\t\tif (j == XATTR_SIZE_MAX)\n+\t\t\treturn -E2BIG;\n+\t\ts__ign++;\n+\t}\n+\treturn -E2BIG;\n+err_out:\n+\treturn -EFAULT;\n+}\n+\n+/**\n+ * bpf_memcmp - Compare two memory regions byte by byte\n+ * @ptr1__ign: First memory region\n+ * @ptr2__ign: Second memory region\n+ * @size: Number of bytes to compare\n+ *\n+ * Compares the first @size bytes of the memory areas @ptr1__ign and\n+ * @ptr2__ign. Unlike bpf_strcmp, null bytes do not terminate the comparison.\n+ *\n+ * Return:\n+ * * %0       - The memory regions are equal\n+ * * %-1      - @ptr1__ign is less than @ptr2__ign\n+ * * %1       - @ptr1__ign is greater than @ptr2__ign\n+ * * %-EFAULT - Cannot read one of the memory regions\n+ * * %-E2BIG  - @size exceeds the maximum allowed size\n+ * * %-ERANGE - One of the memory regions is outside of kernel address space\n+ */\n+__bpf_kfunc int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign,\n+\t\t\t   size_t size)\n+{\n+\tconst unsigned char *p1 = ptr1__ign, *p2 = ptr2__ign;\n+\tunsigned char c1, c2;\n+\tsize_t i;\n+\n+\tif (size \u003e XATTR_SIZE_MAX)\n+\t\treturn -E2BIG;\n+\tif (!copy_from_kernel_nofault_allowed(p1, size) ||\n+\t    !copy_from_kernel_nofault_allowed(p2, size))\n+\t\treturn -ERANGE;\n+\n+\tguard(pagefault)();\n+\tfor (i = 0; i \u003c size; i++) {\n+\t\t__get_kernel_nofault(\u0026c1, p1 + i, char, err_out);\n+\t\t__get_kernel_nofault(\u0026c2, p2 + i, char, err_out);\n+\t\tif (c1 != c2)\n+\t\t\treturn c1 \u003c c2 ? -1 : 1;\n+\t}\n+\treturn 0;\n+err_out:\n+\treturn -EFAULT;\n+}\n+\n static int __bpf_strnstr(const char *s1, const char *s2, size_t len,\n \t\t\t bool ignore_case)\n {\n@@ -4850,6 +4936,8 @@ BTF_ID_FLAGS(func, bpf_strlen);\n BTF_ID_FLAGS(func, bpf_strnlen);\n BTF_ID_FLAGS(func, bpf_strspn);\n BTF_ID_FLAGS(func, bpf_strcspn);\n+BTF_ID_FLAGS(func, bpf_strpbrk);\n+BTF_ID_FLAGS(func, bpf_memcmp);\n BTF_ID_FLAGS(func, bpf_strstr);\n BTF_ID_FLAGS(func, bpf_strcasestr);\n BTF_ID_FLAGS(func, bpf_strnstr);\ndiff --git a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c\nindex 300032a1944514..959ff37110a163 100644\n--- a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c\n+++ b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c\n@@ -20,6 +20,8 @@ static const char * const test_cases[] = {\n \t\"strspn_accept\",\n \t\"strcspn_str\",\n \t\"strcspn_reject\",\n+\t\t\"strpbrk_str\",\n+\t\t\"strpbrk_accept\",\n \t\"strstr\",\n \t\"strcasestr\",\n \t\"strnstr\",\ndiff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c\nindex e0d672d93adf85..071581ff0833f3 100644\n--- a/tools/testing/selftests/bpf/progs/dynptr_success.c\n+++ b/tools/testing/selftests/bpf/progs/dynptr_success.c\n@@ -624,7 +624,7 @@ int BPF_PROG(test_dynptr_skb_tp_btf, void *skb, void *location)\n \treturn 1;\n }\n \n-static inline int bpf_memcmp(const char *a, const char *b, u32 size)\n+static inline int local_memcmp(const char *a, const char *b, u32 size)\n {\n \tint i;\n \n@@ -650,12 +650,12 @@ int test_dynptr_copy(void *ctx)\n \terr = bpf_dynptr_write(\u0026src, 0, data, sz, 0);\n \terr = err ?: bpf_dynptr_copy(\u0026dst, 0, \u0026src, 0, sz);\n \terr = err ?: bpf_dynptr_read(buf, sz, \u0026dst, 0, 0);\n-\terr = err ?: bpf_memcmp(data, buf, sz);\n+\terr = err ?: local_memcmp(data, buf, sz);\n \n \t/* Test that offsets are handled correctly */\n \terr = err ?: bpf_dynptr_copy(\u0026dst, 3, \u0026src, 5, sz - 5);\n \terr = err ?: bpf_dynptr_read(buf, sz - 5, \u0026dst, 3, 0);\n-\terr = err ?: bpf_memcmp(data + 5, buf, sz - 5);\n+\terr = err ?: local_memcmp(data + 5, buf, sz - 5);\n \n \tbpf_ringbuf_discard_dynptr(\u0026src, 0);\n \tbpf_ringbuf_discard_dynptr(\u0026dst, 0);\n@@ -692,7 +692,7 @@ int test_dynptr_copy_xdp(struct xdp_md *xdp)\n \t\terr = bpf_dynptr_read(\u0026buf, len, \u0026ptr_xdp, i * len, 0);\n \t\tif (err)\n \t\t\tgoto out;\n-\t\tif (bpf_memcmp(data, buf, len) != 0)\n+\t\tif (local_memcmp(data, buf, len) != 0)\n \t\t\tgoto out;\n \t}\n \n@@ -713,7 +713,7 @@ int test_dynptr_copy_xdp(struct xdp_md *xdp)\n \t\terr = bpf_dynptr_read(\u0026buf, len, \u0026ptr_buf, i * len, 0);\n \t\tif (err)\n \t\t\tgoto out;\n-\t\tif (bpf_memcmp(data, buf, len) != 0)\n+\t\tif (local_memcmp(data, buf, len) != 0)\n \t\t\tgoto out;\n \t}\n \n@@ -727,7 +727,7 @@ int test_dynptr_copy_xdp(struct xdp_md *xdp)\n \t\terr = bpf_dynptr_read(\u0026buf, len, \u0026ptr_xdp, 2 + i * len, 0);\n \t\tif (err)\n \t\t\tgoto out;\n-\t\tif (bpf_memcmp(data, buf, len) != 0)\n+\t\tif (local_memcmp(data, buf, len) != 0)\n \t\t\tgoto out;\n \t}\n \n@@ -750,7 +750,7 @@ int test_dynptr_memset_zero(void *ctx)\n \n \terr = bpf_dynptr_from_mem(memset_zero_data, data_sz, 0, \u0026ptr);\n \terr = err ?: bpf_dynptr_memset(\u0026ptr, 0, data_sz, 0);\n-\terr = err ?: bpf_memcmp(zeroes, memset_zero_data, data_sz);\n+\terr = err ?: local_memcmp(zeroes, memset_zero_data, data_sz);\n \n \treturn 0;\n }\n@@ -770,7 +770,7 @@ int test_dynptr_memset_notzero(void *ctx)\n \n \terr = bpf_dynptr_from_mem(memset_notzero_data, data_sz, 0, \u0026ptr);\n \terr = err ?: bpf_dynptr_memset(\u0026ptr, 0, data_sz, DYNPTR_MEMSET_VAL);\n-\terr = err ?: bpf_memcmp(expected, memset_notzero_data, data_sz);\n+\terr = err ?: local_memcmp(expected, memset_notzero_data, data_sz);\n \n \treturn 0;\n }\n@@ -786,7 +786,7 @@ int test_dynptr_memset_zero_offset(void *ctx)\n \n \terr = bpf_dynptr_from_mem(memset_zero_offset_data, data_sz, 0, \u0026ptr);\n \terr = err ?: bpf_dynptr_memset(\u0026ptr, 8, 4, 0);\n-\terr = err ?: bpf_memcmp(expected, memset_zero_offset_data, data_sz);\n+\terr = err ?: local_memcmp(expected, memset_zero_offset_data, data_sz);\n \n \treturn 0;\n }\n@@ -803,7 +803,7 @@ int test_dynptr_memset_zero_adjusted(void *ctx)\n \terr = bpf_dynptr_from_mem(memset_zero_adjusted_data, data_sz, 0, \u0026ptr);\n \terr = err ?: bpf_dynptr_adjust(\u0026ptr, 4, 8);\n \terr = err ?: bpf_dynptr_memset(\u0026ptr, 0, bpf_dynptr_size(\u0026ptr), 0);\n-\terr = err ?: bpf_memcmp(expected, memset_zero_adjusted_data, data_sz);\n+\terr = err ?: local_memcmp(expected, memset_zero_adjusted_data, data_sz);\n \n \treturn 0;\n }\n@@ -898,7 +898,7 @@ int test_dynptr_memset_xdp_chunks(struct xdp_md *xdp)\n \t\terr = bpf_dynptr_read(\u0026buf, chunk_sz, \u0026ptr_xdp, offset, 0);\n \t\tif (err)\n \t\t\tgoto out;\n-\t\terr = bpf_memcmp(buf, expected_buf, sizeof(buf));\n+\t\terr = local_memcmp(buf, expected_buf, sizeof(buf));\n \t\tif (err)\n \t\t\tgoto out;\n \t}\n@@ -952,7 +952,7 @@ static __always_inline void test_dynptr_probe(void *ptr, bpf_read_dynptr_fn_t bp\n \t\t\tbreak;\n \t\terr = err ?: bpf_dynptr_read(\u0026buf, len, \u0026ptr_buf, 0, 0);\n \n-\t\tif (err || bpf_memcmp(expected_str, buf, len))\n+\t\tif (err || local_memcmp(expected_str, buf, len))\n \t\t\terr = 1;\n \n \t\t/* Reset buffer and dynptr */\n@@ -986,7 +986,7 @@ static __always_inline void test_dynptr_probe_str(void *ptr,\n \t\terr = err ?: bpf_dynptr_read(\u0026buf, len, \u0026ptr_buf, 0, 0);\n \t\tif (!len)\n \t\t\tcontinue;\n-\t\tif (err || bpf_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\\0')\n+\t\tif (err || local_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\\0')\n \t\t\terr = 1;\n \t}\n \tbpf_ringbuf_discard_dynptr(\u0026ptr_buf, 0);\n@@ -1012,7 +1012,7 @@ static __always_inline void test_dynptr_probe_xdp(struct xdp_md *xdp, void *ptr,\n \t\tif (len \u003e sizeof(buf))\n \t\t\tcontinue;\n \t\terr = err ?: bpf_dynptr_read(\u0026buf, len, \u0026ptr_xdp, off, 0);\n-\t\tif (err || bpf_memcmp(expected_str, buf, len))\n+\t\tif (err || local_memcmp(expected_str, buf, len))\n \t\t\terr = 1;\n \t\t/* Reset buffer and dynptr */\n \t\t__builtin_memset(buf, 0, sizeof(buf));\n@@ -1048,7 +1048,7 @@ static __always_inline void test_dynptr_probe_str_xdp(struct xdp_md *xdp, void *\n \n \t\tif (!len)\n \t\t\tcontinue;\n-\t\tif (err || bpf_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\\0')\n+\t\tif (err || local_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\\0')\n \t\t\terr = 1;\n \n \t\t__builtin_memset(buf, 0, sizeof(buf));\ndiff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c\nindex bddc4e8579d244..e67fe9700e593c 100644\n--- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c\n+++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c\n@@ -9,6 +9,10 @@\n char *user_ptr = (char *)1;\n char *invalid_kern_ptr = (char *)-1;\n \n+extern int bpf_strpbrk(const char *s__ign, const char *accept__ign) __ksym;\n+extern int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign,\n+\t\t      size_t size) __ksym;\n+\n /*\n  * When passing userspace pointers, the error code differs based on arch:\n  *   -ERANGE on arches with non-overlapping address spaces\n@@ -53,6 +57,10 @@ SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_strnstr_null1(void *ctx) { return\n SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_strnstr_null2(void *ctx) { return bpf_strnstr(\"hello\", NULL, 1); }\n SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_strncasestr_null1(void *ctx) { return bpf_strncasestr(NULL, \"hello\", 1); }\n SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_strncasestr_null2(void *ctx) { return bpf_strncasestr(\"hello\", NULL, 1); }\n+SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_memcmp_null1(void *ctx) { return bpf_memcmp(NULL, \"x\", 1); }\n+SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_memcmp_null2(void *ctx) { return bpf_memcmp(\"x\", NULL, 1); }\n+SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_strpbrk_null1(void *ctx) { return bpf_strpbrk(NULL, \"x\"); }\n+SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_strpbrk_null2(void *ctx) { return bpf_strpbrk(\"x\", NULL); }\n \n /* Passing userspace ptr to string kfuncs */\n SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strcmp_user_ptr1(void *ctx) { return bpf_strcmp(user_ptr, \"hello\"); }\n@@ -79,6 +87,10 @@ SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strnstr_user_ptr1(void *ctx) { re\n SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strnstr_user_ptr2(void *ctx) { return bpf_strnstr(\"hello\", user_ptr, 1); }\n SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strncasestr_user_ptr1(void *ctx) { return bpf_strncasestr(user_ptr, \"hello\", 1); }\n SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strncasestr_user_ptr2(void *ctx) { return bpf_strncasestr(\"hello\", user_ptr, 1); }\n+SEC(\"syscall\") __retval(USER_PTR_ERR) int test_memcmp_user_ptr1(void *ctx) { return bpf_memcmp(user_ptr, \"x\", 1); }\n+SEC(\"syscall\") __retval(USER_PTR_ERR) int test_memcmp_user_ptr2(void *ctx) { return bpf_memcmp(\"x\", user_ptr, 1); }\n+SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strpbrk_user_ptr1(void *ctx) { return bpf_strpbrk(user_ptr, \"x\"); }\n+SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strpbrk_user_ptr2(void *ctx) { return bpf_strpbrk(\"x\", user_ptr); }\n \n #endif /* __TARGET_ARCH_s390 */\n \n@@ -107,5 +119,9 @@ SEC(\"syscall\") __retval(-EFAULT) int test_strnstr_pagefault1(void *ctx) { return\n SEC(\"syscall\") __retval(-EFAULT) int test_strnstr_pagefault2(void *ctx) { return bpf_strnstr(\"hello\", invalid_kern_ptr, 1); }\n SEC(\"syscall\") __retval(-EFAULT) int test_strncasestr_pagefault1(void *ctx) { return bpf_strncasestr(invalid_kern_ptr, \"hello\", 1); }\n SEC(\"syscall\") __retval(-EFAULT) int test_strncasestr_pagefault2(void *ctx) { return bpf_strncasestr(\"hello\", invalid_kern_ptr, 1); }\n+SEC(\"syscall\") __retval(-EFAULT) int test_memcmp_pagefault1(void *ctx) { return bpf_memcmp(invalid_kern_ptr, \"x\", 1); }\n+SEC(\"syscall\") __retval(-EFAULT) int test_memcmp_pagefault2(void *ctx) { return bpf_memcmp(\"x\", invalid_kern_ptr, 1); }\n+SEC(\"syscall\") __retval(-EFAULT) int test_strpbrk_pagefault1(void *ctx) { return bpf_strpbrk(invalid_kern_ptr, \"x\"); }\n+SEC(\"syscall\") __retval(-EFAULT) int test_strpbrk_pagefault2(void *ctx) { return bpf_strpbrk(\"x\", invalid_kern_ptr); }\n \n char _license[] SEC(\"license\") = \"GPL\";\ndiff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c b/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c\nindex 412c53b87b182b..d3b978e453bd7c 100644\n--- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c\n+++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c\n@@ -19,6 +19,8 @@ SEC(\"syscall\") int test_strspn_str_too_long(void *ctx) { return bpf_strspn(long_\n SEC(\"syscall\") int test_strspn_accept_too_long(void *ctx) { return bpf_strspn(\"b\", long_str); }\n SEC(\"syscall\") int test_strcspn_str_too_long(void *ctx) { return bpf_strcspn(long_str, \"b\"); }\n SEC(\"syscall\") int test_strcspn_reject_too_long(void *ctx) { return bpf_strcspn(\"b\", long_str); }\n+SEC(\"syscall\") int test_strpbrk_str_too_long(void *ctx) { return bpf_strpbrk(long_str, \"z\"); }\n+SEC(\"syscall\") int test_strpbrk_accept_too_long(void *ctx) { return bpf_strpbrk(\"b\", long_str); }\n SEC(\"syscall\") int test_strstr_too_long(void *ctx) { return bpf_strstr(long_str, \"hello\"); }\n SEC(\"syscall\") int test_strcasestr_too_long(void *ctx) { return bpf_strcasestr(long_str, \"hello\"); }\n SEC(\"syscall\") int test_strnstr_too_long(void *ctx) { return bpf_strnstr(long_str, \"hello\", sizeof(long_str)); }\ndiff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c\nindex f65b1226a81a37..25b8c897da54bc 100644\n--- a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c\n+++ b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c\n@@ -7,6 +7,10 @@\n \n char str[] = \"hello world\";\n \n+extern int bpf_strpbrk(const char *s__ign, const char *accept__ign) __ksym;\n+extern int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign,\n+\t\t      size_t size) __ksym;\n+\n #define __test(retval) SEC(\"syscall\") __success __retval(retval)\n \n /* Functional tests */\n@@ -60,4 +64,25 @@ __test(-ENOENT) int test_strncasestr_notfound2(void *ctx) { return bpf_strncases\n __test(-ENOENT) int test_strncasestr_notfound3(void *ctx) { return bpf_strncasestr(\"\", \"a\", 0); }\n __test(0) int test_strncasestr_empty(void *ctx) { return bpf_strncasestr(str, \"\", 1); }\n \n+/* bpf_strpbrk - functional tests */\n+__test(0) int test_strpbrk_found_first(void *ctx) { return bpf_strpbrk(str, \"h\"); }\n+__test(4) int test_strpbrk_found_middle(void *ctx) { return bpf_strpbrk(str, \"ow\"); }\n+__test(2) int test_strpbrk_found_multiple(void *ctx) { return bpf_strpbrk(str, \"l\"); }\n+__test(-ENOENT) int test_strpbrk_notfound(void *ctx) { return bpf_strpbrk(str, \"xyz\"); }\n+__test(-ENOENT) int test_strpbrk_empty_accept(void *ctx) { return bpf_strpbrk(str, \"\"); }\n+\n+/* bpf_memcmp - functional tests */\n+char data1[] = \"hello world\";\n+char data2[] = \"hello world\";\n+char data3[] = \"hello worle\";\n+__test(0) int test_memcmp_eq(void *ctx) { return bpf_memcmp(data1, data2, sizeof(data1)); }\n+__test(-1) int test_memcmp_neq_less(void *ctx) { return bpf_memcmp(data1, data3, sizeof(data1)); }\n+__test(1) int test_memcmp_neq_greater(void *ctx) { return bpf_memcmp(data3, data1, sizeof(data1)); }\n+__test(0) int test_memcmp_size_zero(void *ctx) { return bpf_memcmp(data1, data3, 0); }\n+/* memcmp should NOT stop at null byte - compare past '\\0' */\n+char bin1[] = { 'a', '\\0', 'c' };\n+char bin2[] = { 'a', '\\0', 'd' };\n+__test(0) int test_memcmp_null_byte_eq(void *ctx) { return bpf_memcmp(bin1, bin1, sizeof(bin1)); }\n+__test(-1) int test_memcmp_null_byte_neq(void *ctx) { return bpf_memcmp(bin1, bin2, sizeof(bin1)); }\n+\n char _license[] SEC(\"license\") = \"GPL\";\n"
}

2/1 2026/06/26 15:33 agent patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL"
  ],
  "FocusSymbols": [
    "bpf_strpbrk",
    "bpf_memcmp"
  ],
  "Reasoning": "The patch introduces two new BPF kfuncs, bpf_strpbrk and bpf_memcmp, which can be called from BPF programs. These are functional additions to the core BPF helper library and should be fuzzed.",
  "WorthFuzzing": true
}

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).

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.
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.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. 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 78fad54457c40244496e8ce00bc41cb77a6c51fb
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Jun 26 15:33:56 2026 +0000

    syz-cluster: applied patch under review

diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index b5314c9fed3cf0..ead00ec314f54a 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -3971,6 +3971,92 @@ __bpf_kfunc int bpf_strcspn(const char *s__ign, const char *reject__ign)
 	return -EFAULT;
 }
 
+/**
+ * bpf_strpbrk - Find the first occurrence of a set of characters in a string
+ * @s__ign: The string to be searched
+ * @accept__ign: The string containing the characters to search for
+ *
+ * Return:
+ * * >=0      - Index of the first character in @s__ign that matches any
+ *              character in @accept__ign
+ * * %-ENOENT - No character of @accept__ign found in @s__ign
+ * * %-EFAULT - Cannot read one of the strings
+ * * %-E2BIG  - One of the strings is too large
+ * * %-ERANGE - One of the strings is outside of kernel address space
+ */
+__bpf_kfunc int bpf_strpbrk(const char *s__ign, const char *accept__ign)
+{
+	char cs, ca;
+	int i, j;
+
+	if (!copy_from_kernel_nofault_allowed(s__ign, 1) ||
+	    !copy_from_kernel_nofault_allowed(accept__ign, 1)) {
+		return -ERANGE;
+	}
+
+	guard(pagefault)();
+	for (i = 0; i < XATTR_SIZE_MAX; i++) {
+		__get_kernel_nofault(&cs, s__ign, char, err_out);
+		if (cs == '\0')
+			return -ENOENT;
+		for (j = 0; j < XATTR_SIZE_MAX; j++) {
+			__get_kernel_nofault(&ca, accept__ign + j, char, err_out);
+			if (ca == '\0')
+				break;
+			if (cs == ca)
+				return i;
+		}
+		if (j == XATTR_SIZE_MAX)
+			return -E2BIG;
+		s__ign++;
+	}
+	return -E2BIG;
+err_out:
+	return -EFAULT;
+}
+
+/**
+ * bpf_memcmp - Compare two memory regions byte by byte
+ * @ptr1__ign: First memory region
+ * @ptr2__ign: Second memory region
+ * @size: Number of bytes to compare
+ *
+ * Compares the first @size bytes of the memory areas @ptr1__ign and
+ * @ptr2__ign. Unlike bpf_strcmp, null bytes do not terminate the comparison.
+ *
+ * Return:
+ * * %0       - The memory regions are equal
+ * * %-1      - @ptr1__ign is less than @ptr2__ign
+ * * %1       - @ptr1__ign is greater than @ptr2__ign
+ * * %-EFAULT - Cannot read one of the memory regions
+ * * %-E2BIG  - @size exceeds the maximum allowed size
+ * * %-ERANGE - One of the memory regions is outside of kernel address space
+ */
+__bpf_kfunc int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign,
+			   size_t size)
+{
+	const unsigned char *p1 = ptr1__ign, *p2 = ptr2__ign;
+	unsigned char c1, c2;
+	size_t i;
+
+	if (size > XATTR_SIZE_MAX)
+		return -E2BIG;
+	if (!copy_from_kernel_nofault_allowed(p1, size) ||
+	    !copy_from_kernel_nofault_allowed(p2, size))
+		return -ERANGE;
+
+	guard(pagefault)();
+	for (i = 0; i < size; i++) {
+		__get_kernel_nofault(&c1, p1 + i, char, err_out);
+		__get_kernel_nofault(&c2, p2 + i, char, err_out);
+		if (c1 != c2)
+			return c1 < c2 ? -1 : 1;
+	}
+	return 0;
+err_out:
+	return -EFAULT;
+}
+
 static int __bpf_strnstr(const char *s1, const char *s2, size_t len,
 			 bool ignore_case)
 {
@@ -4850,6 +4936,8 @@ BTF_ID_FLAGS(func, bpf_strlen);
 BTF_ID_FLAGS(func, bpf_strnlen);
 BTF_ID_FLAGS(func, bpf_strspn);
 BTF_ID_FLAGS(func, bpf_strcspn);
+BTF_ID_FLAGS(func, bpf_strpbrk);
+BTF_ID_FLAGS(func, bpf_memcmp);
 BTF_ID_FLAGS(func, bpf_strstr);
 BTF_ID_FLAGS(func, bpf_strcasestr);
 BTF_ID_FLAGS(func, bpf_strnstr);
diff --git a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c
index 300032a1944514..959ff37110a163 100644
--- a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c
+++ b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c
@@ -20,6 +20,8 @@ static const char * const test_cases[] = {
 	"strspn_accept",
 	"strcspn_str",
 	"strcspn_reject",
+		"strpbrk_str",
+		"strpbrk_accept",
 	"strstr",
 	"strcasestr",
 	"strnstr",
diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c
index e0d672d93adf85..071581ff0833f3 100644
--- a/tools/testing/selftests/bpf/progs/dynptr_success.c
+++ b/tools/testing/selftests/bpf/progs/dynptr_success.c
@@ -624,7 +624,7 @@ int BPF_PROG(test_dynptr_skb_tp_btf, void *skb, void *location)
 	return 1;
 }
 
-static inline int bpf_memcmp(const char *a, const char *b, u32 size)
+static inline int local_memcmp(const char *a, const char *b, u32 size)
 {
 	int i;
 
@@ -650,12 +650,12 @@ int test_dynptr_copy(void *ctx)
 	err = bpf_dynptr_write(&src, 0, data, sz, 0);
 	err = err ?: bpf_dynptr_copy(&dst, 0, &src, 0, sz);
 	err = err ?: bpf_dynptr_read(buf, sz, &dst, 0, 0);
-	err = err ?: bpf_memcmp(data, buf, sz);
+	err = err ?: local_memcmp(data, buf, sz);
 
 	/* Test that offsets are handled correctly */
 	err = err ?: bpf_dynptr_copy(&dst, 3, &src, 5, sz - 5);
 	err = err ?: bpf_dynptr_read(buf, sz - 5, &dst, 3, 0);
-	err = err ?: bpf_memcmp(data + 5, buf, sz - 5);
+	err = err ?: local_memcmp(data + 5, buf, sz - 5);
 
 	bpf_ringbuf_discard_dynptr(&src, 0);
 	bpf_ringbuf_discard_dynptr(&dst, 0);
@@ -692,7 +692,7 @@ int test_dynptr_copy_xdp(struct xdp_md *xdp)
 		err = bpf_dynptr_read(&buf, len, &ptr_xdp, i * len, 0);
 		if (err)
 			goto out;
-		if (bpf_memcmp(data, buf, len) != 0)
+		if (local_memcmp(data, buf, len) != 0)
 			goto out;
 	}
 
@@ -713,7 +713,7 @@ int test_dynptr_copy_xdp(struct xdp_md *xdp)
 		err = bpf_dynptr_read(&buf, len, &ptr_buf, i * len, 0);
 		if (err)
 			goto out;
-		if (bpf_memcmp(data, buf, len) != 0)
+		if (local_memcmp(data, buf, len) != 0)
 			goto out;
 	}
 
@@ -727,7 +727,7 @@ int test_dynptr_copy_xdp(struct xdp_md *xdp)
 		err = bpf_dynptr_read(&buf, len, &ptr_xdp, 2 + i * len, 0);
 		if (err)
 			goto out;
-		if (bpf_memcmp(data, buf, len) != 0)
+		if (local_memcmp(data, buf, len) != 0)
 			goto out;
 	}
 
@@ -750,7 +750,7 @@ int test_dynptr_memset_zero(void *ctx)
 
 	err = bpf_dynptr_from_mem(memset_zero_data, data_sz, 0, &ptr);
 	err = err ?: bpf_dynptr_memset(&ptr, 0, data_sz, 0);
-	err = err ?: bpf_memcmp(zeroes, memset_zero_data, data_sz);
+	err = err ?: local_memcmp(zeroes, memset_zero_data, data_sz);
 
 	return 0;
 }
@@ -770,7 +770,7 @@ int test_dynptr_memset_notzero(void *ctx)
 
 	err = bpf_dynptr_from_mem(memset_notzero_data, data_sz, 0, &ptr);
 	err = err ?: bpf_dynptr_memset(&ptr, 0, data_sz, DYNPTR_MEMSET_VAL);
-	err = err ?: bpf_memcmp(expected, memset_notzero_data, data_sz);
+	err = err ?: local_memcmp(expected, memset_notzero_data, data_sz);
 
 	return 0;
 }
@@ -786,7 +786,7 @@ int test_dynptr_memset_zero_offset(void *ctx)
 
 	err = bpf_dynptr_from_mem(memset_zero_offset_data, data_sz, 0, &ptr);
 	err = err ?: bpf_dynptr_memset(&ptr, 8, 4, 0);
-	err = err ?: bpf_memcmp(expected, memset_zero_offset_data, data_sz);
+	err = err ?: local_memcmp(expected, memset_zero_offset_data, data_sz);
 
 	return 0;
 }
@@ -803,7 +803,7 @@ int test_dynptr_memset_zero_adjusted(void *ctx)
 	err = bpf_dynptr_from_mem(memset_zero_adjusted_data, data_sz, 0, &ptr);
 	err = err ?: bpf_dynptr_adjust(&ptr, 4, 8);
 	err = err ?: bpf_dynptr_memset(&ptr, 0, bpf_dynptr_size(&ptr), 0);
-	err = err ?: bpf_memcmp(expected, memset_zero_adjusted_data, data_sz);
+	err = err ?: local_memcmp(expected, memset_zero_adjusted_data, data_sz);
 
 	return 0;
 }
@@ -898,7 +898,7 @@ int test_dynptr_memset_xdp_chunks(struct xdp_md *xdp)
 		err = bpf_dynptr_read(&buf, chunk_sz, &ptr_xdp, offset, 0);
 		if (err)
 			goto out;
-		err = bpf_memcmp(buf, expected_buf, sizeof(buf));
+		err = local_memcmp(buf, expected_buf, sizeof(buf));
 		if (err)
 			goto out;
 	}
@@ -952,7 +952,7 @@ static __always_inline void test_dynptr_probe(void *ptr, bpf_read_dynptr_fn_t bp
 			break;
 		err = err ?: bpf_dynptr_read(&buf, len, &ptr_buf, 0, 0);
 
-		if (err || bpf_memcmp(expected_str, buf, len))
+		if (err || local_memcmp(expected_str, buf, len))
 			err = 1;
 
 		/* Reset buffer and dynptr */
@@ -986,7 +986,7 @@ static __always_inline void test_dynptr_probe_str(void *ptr,
 		err = err ?: bpf_dynptr_read(&buf, len, &ptr_buf, 0, 0);
 		if (!len)
 			continue;
-		if (err || bpf_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\0')
+		if (err || local_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\0')
 			err = 1;
 	}
 	bpf_ringbuf_discard_dynptr(&ptr_buf, 0);
@@ -1012,7 +1012,7 @@ static __always_inline void test_dynptr_probe_xdp(struct xdp_md *xdp, void *ptr,
 		if (len > sizeof(buf))
 			continue;
 		err = err ?: bpf_dynptr_read(&buf, len, &ptr_xdp, off, 0);
-		if (err || bpf_memcmp(expected_str, buf, len))
+		if (err || local_memcmp(expected_str, buf, len))
 			err = 1;
 		/* Reset buffer and dynptr */
 		__builtin_memset(buf, 0, sizeof(buf));
@@ -1048,7 +1048,7 @@ static __always_inline void test_dynptr_probe_str_xdp(struct xdp_md *xdp, void *
 
 		if (!len)
 			continue;
-		if (err || bpf_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\0')
+		if (err || local_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\0')
 			err = 1;
 
 		__builtin_memset(buf, 0, sizeof(buf));
diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c
index bddc4e8579d244..e67fe9700e593c 100644
--- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c
+++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c
@@ -9,6 +9,10 @@
 char *user_ptr = (char *)1;
 char *invalid_kern_ptr = (char *)-1;
 
+extern int bpf_strpbrk(const char *s__ign, const char *accept__ign) __ksym;
+extern int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign,
+		      size_t size) __ksym;
+
 /*
  * When passing userspace pointers, the error code differs based on arch:
  *   -ERANGE on arches with non-overlapping address spaces
@@ -53,6 +57,10 @@ SEC("syscall")  __retval(USER_PTR_ERR)int test_strnstr_null1(void *ctx) { return
 SEC("syscall")  __retval(USER_PTR_ERR)int test_strnstr_null2(void *ctx) { return bpf_strnstr("hello", NULL, 1); }
 SEC("syscall")  __retval(USER_PTR_ERR)int test_strncasestr_null1(void *ctx) { return bpf_strncasestr(NULL, "hello", 1); }
 SEC("syscall")  __retval(USER_PTR_ERR)int test_strncasestr_null2(void *ctx) { return bpf_strncasestr("hello", NULL, 1); }
+SEC("syscall")  __retval(USER_PTR_ERR)int test_memcmp_null1(void *ctx) { return bpf_memcmp(NULL, "x", 1); }
+SEC("syscall")  __retval(USER_PTR_ERR)int test_memcmp_null2(void *ctx) { return bpf_memcmp("x", NULL, 1); }
+SEC("syscall")  __retval(USER_PTR_ERR)int test_strpbrk_null1(void *ctx) { return bpf_strpbrk(NULL, "x"); }
+SEC("syscall")  __retval(USER_PTR_ERR)int test_strpbrk_null2(void *ctx) { return bpf_strpbrk("x", NULL); }
 
 /* Passing userspace ptr to string kfuncs */
 SEC("syscall") __retval(USER_PTR_ERR) int test_strcmp_user_ptr1(void *ctx) { return bpf_strcmp(user_ptr, "hello"); }
@@ -79,6 +87,10 @@ SEC("syscall") __retval(USER_PTR_ERR) int test_strnstr_user_ptr1(void *ctx) { re
 SEC("syscall") __retval(USER_PTR_ERR) int test_strnstr_user_ptr2(void *ctx) { return bpf_strnstr("hello", user_ptr, 1); }
 SEC("syscall") __retval(USER_PTR_ERR) int test_strncasestr_user_ptr1(void *ctx) { return bpf_strncasestr(user_ptr, "hello", 1); }
 SEC("syscall") __retval(USER_PTR_ERR) int test_strncasestr_user_ptr2(void *ctx) { return bpf_strncasestr("hello", user_ptr, 1); }
+SEC("syscall") __retval(USER_PTR_ERR) int test_memcmp_user_ptr1(void *ctx) { return bpf_memcmp(user_ptr, "x", 1); }
+SEC("syscall") __retval(USER_PTR_ERR) int test_memcmp_user_ptr2(void *ctx) { return bpf_memcmp("x", user_ptr, 1); }
+SEC("syscall") __retval(USER_PTR_ERR) int test_strpbrk_user_ptr1(void *ctx) { return bpf_strpbrk(user_ptr, "x"); }
+SEC("syscall") __retval(USER_PTR_ERR) int test_strpbrk_user_ptr2(void *ctx) { return bpf_strpbrk("x", user_ptr); }
 
 #endif /* __TARGET_ARCH_s390 */
 
@@ -107,5 +119,9 @@ SEC("syscall") __retval(-EFAULT) int test_strnstr_pagefault1(void *ctx) { return
 SEC("syscall") __retval(-EFAULT) int test_strnstr_pagefault2(void *ctx) { return bpf_strnstr("hello", invalid_kern_ptr, 1); }
 SEC("syscall") __retval(-EFAULT) int test_strncasestr_pagefault1(void *ctx) { return bpf_strncasestr(invalid_kern_ptr, "hello", 1); }
 SEC("syscall") __retval(-EFAULT) int test_strncasestr_pagefault2(void *ctx) { return bpf_strncasestr("hello", invalid_kern_ptr, 1); }
+SEC("syscall") __retval(-EFAULT) int test_memcmp_pagefault1(void *ctx) { return bpf_memcmp(invalid_kern_ptr, "x", 1); }
+SEC("syscall") __retval(-EFAULT) int test_memcmp_pagefault2(void *ctx) { return bpf_memcmp("x", invalid_kern_ptr, 1); }
+SEC("syscall") __retval(-EFAULT) int test_strpbrk_pagefault1(void *ctx) { return bpf_strpbrk(invalid_kern_ptr, "x"); }
+SEC("syscall") __retval(-EFAULT) int test_strpbrk_pagefault2(void *ctx) { return bpf_strpbrk("x", invalid_kern_ptr); }
 
 char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c b/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c
index 412c53b87b182b..d3b978e453bd7c 100644
--- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c
+++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c
@@ -19,6 +19,8 @@ SEC("syscall") int test_strspn_str_too_long(void *ctx) { return bpf_strspn(long_
 SEC("syscall") int test_strspn_accept_too_long(void *ctx) { return bpf_strspn("b", long_str); }
 SEC("syscall") int test_strcspn_str_too_long(void *ctx) { return bpf_strcspn(long_str, "b"); }
 SEC("syscall") int test_strcspn_reject_too_long(void *ctx) { return bpf_strcspn("b", long_str); }
+SEC("syscall") int test_strpbrk_str_too_long(void *ctx) { return bpf_strpbrk(long_str, "z"); }
+SEC("syscall") int test_strpbrk_accept_too_long(void *ctx) { return bpf_strpbrk("b", long_str); }
 SEC("syscall") int test_strstr_too_long(void *ctx) { return bpf_strstr(long_str, "hello"); }
 SEC("syscall") int test_strcasestr_too_long(void *ctx) { return bpf_strcasestr(long_str, "hello"); }
 SEC("syscall") int test_strnstr_too_long(void *ctx) { return bpf_strnstr(long_str, "hello", sizeof(long_str)); }
diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c
index f65b1226a81a37..25b8c897da54bc 100644
--- a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c
+++ b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c
@@ -7,6 +7,10 @@
 
 char str[] = "hello world";
 
+extern int bpf_strpbrk(const char *s__ign, const char *accept__ign) __ksym;
+extern int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign,
+		      size_t size) __ksym;
+
 #define __test(retval) SEC("syscall") __success __retval(retval)
 
 /* Functional tests */
@@ -60,4 +64,25 @@ __test(-ENOENT) int test_strncasestr_notfound2(void *ctx) { return bpf_strncases
 __test(-ENOENT) int test_strncasestr_notfound3(void *ctx) { return bpf_strncasestr("", "a", 0); }
 __test(0) int test_strncasestr_empty(void *ctx) { return bpf_strncasestr(str, "", 1); }
 
+/* bpf_strpbrk - functional tests */
+__test(0) int test_strpbrk_found_first(void *ctx) { return bpf_strpbrk(str, "h"); }
+__test(4) int test_strpbrk_found_middle(void *ctx) { return bpf_strpbrk(str, "ow"); }
+__test(2) int test_strpbrk_found_multiple(void *ctx) { return bpf_strpbrk(str, "l"); }
+__test(-ENOENT) int test_strpbrk_notfound(void *ctx) { return bpf_strpbrk(str, "xyz"); }
+__test(-ENOENT) int test_strpbrk_empty_accept(void *ctx) { return bpf_strpbrk(str, ""); }
+
+/* bpf_memcmp - functional tests */
+char data1[] = "hello world";
+char data2[] = "hello world";
+char data3[] = "hello worle";
+__test(0) int test_memcmp_eq(void *ctx) { return bpf_memcmp(data1, data2, sizeof(data1)); }
+__test(-1) int test_memcmp_neq_less(void *ctx) { return bpf_memcmp(data1, data3, sizeof(data1)); }
+__test(1) int test_memcmp_neq_greater(void *ctx) { return bpf_memcmp(data3, data1, sizeof(data1)); }
+__test(0) int test_memcmp_size_zero(void *ctx) { return bpf_memcmp(data1, data3, 0); }
+/* memcmp should NOT stop at null byte - compare past '\0' */
+char bin1[] = { 'a', '\0', 'c' };
+char bin2[] = { 'a', '\0', 'd' };
+__test(0) int test_memcmp_null_byte_eq(void *ctx) { return bpf_memcmp(bin1, bin1, sizeof(bin1)); }
+__test(-1) int test_memcmp_null_byte_neq(void *ctx) { return bpf_memcmp(bin1, bin2, sizeof(bin1)); }
+
 char _license[] SEC("license") = "GPL";

3/2 2026/06/26 15:33 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 8582
							output: 21
							thoughts: 214
						

Thoughts:
**Fuzzing Plan for New BPF Kfuncs**

Okay, so we've got a new patch introducing `bpf_strpbrk` and `bpf_memcmp` as BPF kfuncs. This is interesting – new functionality exposed to BPF programs. Since this code is, by design, reachable from userspace via loaded and running BPF programs, fuzzing is definitely warranted. This is important to ensure the new kfuncs can withstand hostile input.

First, let's nail down the critical symbols: `bpf_strpbrk` and `bpf_memcmp`. Those are the entry points we'll be targeting.

Next, we need to verify the necessary configuration requirements. I'll need to check `kernel/bpf/helpers.c` and `kernel/bpf/Makefile` to confirm, but I'm betting we'll need `CONFIG_BPF_SYSCALL` (or possibly just `CONFIG_BPF`, but more likely the former) enabled. I need to be sure the build and runtime environments are suitable.

Once I have verified these configurations, I will use the available fuzzing tools to test these new kfuncs.



4/2 2026/06/26 15:34 tool grepper
0m Args:
{
  "Expression": "bpf_strpbrk"
}

Results:
{
  "Output": "kernel/bpf/helpers.c=3943=__bpf_kfunc int bpf_strcspn(const char *s__ign, const char *reject__ign)\n--\nkernel/bpf/helpers.c-3974-/**\nkernel/bpf/helpers.c:3975: * bpf_strpbrk - Find the first occurrence of a set of characters in a string\nkernel/bpf/helpers.c-3976- * @s__ign: The string to be searched\n--\nkernel/bpf/helpers.c-3986- */\nkernel/bpf/helpers.c:3987:__bpf_kfunc int bpf_strpbrk(const char *s__ign, const char *accept__ign)\nkernel/bpf/helpers.c-3988-{\n--\nkernel/bpf/helpers.c=4938=BTF_ID_FLAGS(func, bpf_strcspn);\nkernel/bpf/helpers.c:4939:BTF_ID_FLAGS(func, bpf_strpbrk);\nkernel/bpf/helpers.c-4940-BTF_ID_FLAGS(func, bpf_memcmp);\n--\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c=10=char *invalid_kern_ptr = (char *)-1;\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c-11-\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c:12:extern int bpf_strpbrk(const char *s__ign, const char *accept__ign) __ksym;\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c-13-extern int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign,\n--\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c=61=SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_memcmp_null2(void *ctx) { return bpf_memcmp(\"x\", NULL, 1); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c:62:SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_strpbrk_null1(void *ctx) { return bpf_strpbrk(NULL, \"x\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c:63:SEC(\"syscall\")  __retval(USER_PTR_ERR)int test_strpbrk_null2(void *ctx) { return bpf_strpbrk(\"x\", NULL); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c-64-\n--\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c=91=SEC(\"syscall\") __retval(USER_PTR_ERR) int test_memcmp_user_ptr2(void *ctx) { return bpf_memcmp(\"x\", user_ptr, 1); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c:92:SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strpbrk_user_ptr1(void *ctx) { return bpf_strpbrk(user_ptr, \"x\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c:93:SEC(\"syscall\") __retval(USER_PTR_ERR) int test_strpbrk_user_ptr2(void *ctx) { return bpf_strpbrk(\"x\", user_ptr); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c-94-\n--\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c=123=SEC(\"syscall\") __retval(-EFAULT) int test_memcmp_pagefault2(void *ctx) { return bpf_memcmp(\"x\", invalid_kern_ptr, 1); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c:124:SEC(\"syscall\") __retval(-EFAULT) int test_strpbrk_pagefault1(void *ctx) { return bpf_strpbrk(invalid_kern_ptr, \"x\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c:125:SEC(\"syscall\") __retval(-EFAULT) int test_strpbrk_pagefault2(void *ctx) { return bpf_strpbrk(\"x\", invalid_kern_ptr); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure1.c-126-\n--\ntools/testing/selftests/bpf/progs/string_kfuncs_failure2.c=21=SEC(\"syscall\") int test_strcspn_reject_too_long(void *ctx) { return bpf_strcspn(\"b\", long_str); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure2.c:22:SEC(\"syscall\") int test_strpbrk_str_too_long(void *ctx) { return bpf_strpbrk(long_str, \"z\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure2.c:23:SEC(\"syscall\") int test_strpbrk_accept_too_long(void *ctx) { return bpf_strpbrk(\"b\", long_str); }\ntools/testing/selftests/bpf/progs/string_kfuncs_failure2.c-24-SEC(\"syscall\") int test_strstr_too_long(void *ctx) { return bpf_strstr(long_str, \"hello\"); }\n--\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c=8=char str[] = \"hello world\";\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c-9-\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c:10:extern int bpf_strpbrk(const char *s__ign, const char *accept__ign) __ksym;\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c-11-extern int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign,\n--\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c=65=__test(0) int test_strncasestr_empty(void *ctx) { return bpf_strncasestr(str, \"\", 1); }\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c-66-\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c:67:/* bpf_strpbrk - functional tests */\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c:68:__test(0) int test_strpbrk_found_first(void *ctx) { return bpf_strpbrk(str, \"h\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c:69:__test(4) int test_strpbrk_found_middle(void *ctx) { return bpf_strpbrk(str, \"ow\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c:70:__test(2) int test_strpbrk_found_multiple(void *ctx) { return bpf_strpbrk(str, \"l\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c:71:__test(-ENOENT) int test_strpbrk_notfound(void *ctx) { return bpf_strpbrk(str, \"xyz\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c:72:__test(-ENOENT) int test_strpbrk_empty_accept(void *ctx) { return bpf_strpbrk(str, \"\"); }\ntools/testing/selftests/bpf/progs/string_kfuncs_success.c-73-\n"
}

5/2 2026/06/26 15:34 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11218
							output: 29
							thoughts: 50
						

Thoughts:
Okay, here's my take on those thoughts, framed as my own:

**Analyzing the New BPF Helpers**

Alright, so `bpf_strpbrk` and `bpf_memcmp` have been added to `kernel/bpf/helpers.c`. Interesting. My initial thought is to immediately understand the context and how these are exposed. Adding these primitives is a significant step, as they greatly expand the potential functionality of BPF programs. My immediate next step is to look at the relevant configuration options. Understanding which config flags enable `kernel/bpf/helpers.c` is crucial. It’s important to understand the interplay between kernel features and the BPF subsystem, especially as this is a core file. I need to quickly identify the dependencies to ensure these functions are accessible and compiled in my current kernel configuration.



6/2 2026/06/26 15:34 tool grepper
0m Args:
{
  "Expression": "helpers.o",
  "PathPrefix": "kernel/bpf/Makefile"
}

Results:
{
  "Output": "kernel/bpf/Makefile=7=CFLAGS_core.o += -Wno-override-init $(cflags-nogcse-yy)\nkernel/bpf/Makefile-8-\nkernel/bpf/Makefile:9:obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o liveness.o const_fold.o\nkernel/bpf/Makefile-10-obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o\n"
}

7/2 2026/06/26 15:34 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11631
							output: 107
							thoughts: 187
						

Thoughts:
**My Assessment of the New BPF Functionality**

Okay, so I've examined this patch, and it boils down to this: `CONFIG_BPF_SYSCALL` is the key configuration option here. My focus is on the functions `bpf_strpbrk` and `bpf_memcmp`. It's clear that these are functional additions; they're *intended* to do something useful.

I quickly double-checked the code, and yes, these functions are added unconditionally within `kernel/bpf/helpers.c`. That means `CONFIG_BPF_SYSCALL` is the only config we need to enable. No need to worry about any other conditional compilation.

Therefore, my recommendation is straightforward: These new BPF kfuncs, particularly `bpf_strpbrk` and `bpf_memcmp`, are prime targets for fuzzing. They represent new functionality that's now available to BPF programs. They should be prioritized.



8/2 2026/06/26 15:34 tool set-results
0m Args:
{
  "EnableConfigs": [
    "BPF_SYSCALL"
  ],
  "FocusSymbols": [
    "bpf_strpbrk",
    "bpf_memcmp"
  ],
  "Reasoning": "The patch introduces two new BPF kfuncs, bpf_strpbrk and bpf_memcmp, which can be called from BPF programs. These are functional additions to the core BPF helper library and should be fuzzed.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL"
  ],
  "FocusSymbols": [
    "bpf_strpbrk",
    "bpf_memcmp"
  ],
  "Reasoning": "The patch introduces two new BPF kfuncs, bpf_strpbrk and bpf_memcmp, which can be called from BPF programs. These are functional additions to the core BPF helper library and should be fuzzed.",
  "WorthFuzzing": true
}

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)