* [PATCH bpf-next v3 1/2] bpf: add bpf_strcat,bpf_strncat kfunc [not found] <cover.1784194024.git.rtoax@foxmail.com> @ 2026-07-16 9:34 ` Rong Tao 2026-07-16 9:47 ` sashiko-bot 2026-07-17 7:30 ` Viktor Malik 2026-07-16 9:34 ` [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs Rong Tao 1 sibling, 2 replies; 7+ messages in thread From: Rong Tao @ 2026-07-16 9:34 UTC (permalink / raw) To: vmalik, andrii, ast Cc: Rong Tao, Daniel Borkmann, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan, Yuzuki Ishiyama, open list:BPF [GENERAL] (Safe Dynamic Programs and Tools), open list, open list:KERNEL SELFTEST FRAMEWORK From: Rong Tao <rongtao@cestc.cn> Add string concatenation kfuncs, prototype: int bpf_strcat(char *dst, u32 dst__sz, const char *src__ign); int bpf_strncat(char *dst, u32 dst__sz, const char *src__ign, u32 len); This differs from the glibc library functions strcat and strncat, which, for safety reasons, require the size of the target string's memory space as a parameter. Signed-off-by: Rong Tao <rongtao@cestc.cn> --- kernel/bpf/helpers.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index c18f1e16edee..e4708a4f3470 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -4195,6 +4195,97 @@ __bpf_kfunc int bpf_strncasestr(const char *s1__ign, const char *s2__ign, return __bpf_strnstr(s1__ign, s2__ign, len, true); } +static int __bpf_strncat(char *dst, u32 dsz, const char *src, u32 sz) +{ + int dlen, slen, space, copied; + char cs; + + if (!copy_from_kernel_nofault_allowed(dst, 1) || + !copy_from_kernel_nofault_allowed(src, 1)) { + return -ERANGE; + } + + dlen = bpf_strnlen(dst, dsz); + if (dlen < 0) + return dlen; + slen = bpf_strnlen(src, sz); + if (slen < 0) + return slen; + + if (dlen >= dsz || sz == 0 || dsz == 0) + return -EINVAL; + + space = dsz - dlen; + if (space <= 1 || space < min(slen, sz) + 1) + return -E2BIG; + + guard(pagefault)(); + + copied = strncpy_from_kernel_nofault(dst + dlen, src, + min(space, sz + 1)); + if (copied < 0) + return copied; + else if (copied == 0 || copied == 1) + return dlen; + + /* The copied character count includes '\0'. */ + copied--; + + if (copied < sz) { + __get_kernel_nofault(&cs, src + copied, char, err_out); + if (cs != '\0' && sz > copied) + return -E2BIG; + } + + return dlen + copied; +err_out: + return -EFAULT; +} + +/** + * bpf_strcat - Append non-null bytes from a source string, and null-terminate + * the result + * @dst: Destination string. + * @dst__sz: Maximum bytes of @dst__ign, includes the trailing NUL. + * @src__ign: Source string. + * + * Return: + * * >=0 - Length of the concatenated string. + * + * * %-EINVAL - String @dst__ign is invalid. + * * %-EFAULT - Cannot read or write one of the strings. + * * %-E2BIG - String @src__ign is too large or the remaining space in + * @dst__ign is too small. + * * %-ERANGE - One of the strings is outside of kernel address space + */ +__bpf_kfunc int bpf_strcat(char *dst, u32 dst__sz, const char *src__ign) +{ + return __bpf_strncat(dst, dst__sz, src__ign, XATTR_SIZE_MAX); +} + +/** + * bpf_strncat - Append non-null bytes from a source string, and null-terminate + * the result + * @dst: Destination string. + * @dst__sz: Maximum bytes of @dst__ign, includes the trailing NUL. + * @src__ign: Source string. + * @len: the maximum number of characters to concatenate + * + * Return: + * * >=0 - Length of the concatenated string. + * + * * %-EINVAL - String @dst__ign is invalid. + * * %-EFAULT - Cannot read or write one of the strings. + * * %-E2BIG - String @src__ign is too large or the remaining space in + * @dst__ign is too small. + * * %-ERANGE - One of the strings is outside of kernel address space + */ +__bpf_kfunc int bpf_strncat(char *dst, u32 dst__sz, const char *src__ign, + u32 len) +{ + return __bpf_strncat(dst, dst__sz, src__ign, len); +} + #ifdef CONFIG_KEYS /** * bpf_lookup_user_key - lookup a key by its serial @@ -4958,6 +5049,8 @@ BTF_ID_FLAGS(func, bpf_strstr); BTF_ID_FLAGS(func, bpf_strcasestr); BTF_ID_FLAGS(func, bpf_strnstr); BTF_ID_FLAGS(func, bpf_strncasestr); +BTF_ID_FLAGS(func, bpf_strcat); +BTF_ID_FLAGS(func, bpf_strncat); #if defined(CONFIG_BPF_LSM) && defined(CONFIG_CGROUPS) BTF_ID_FLAGS(func, bpf_cgroup_read_xattr, KF_RCU) #endif -- 2.55.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpf: add bpf_strcat,bpf_strncat kfunc 2026-07-16 9:34 ` [PATCH bpf-next v3 1/2] bpf: add bpf_strcat,bpf_strncat kfunc Rong Tao @ 2026-07-16 9:47 ` sashiko-bot 2026-07-17 7:30 ` Viktor Malik 1 sibling, 0 replies; 7+ messages in thread From: sashiko-bot @ 2026-07-16 9:47 UTC (permalink / raw) To: Rong Tao; +Cc: bpf Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] bpf_strncat performs a 1-byte out-of-bounds read on the source string when it is not null-terminated within the requested length, causing a spurious -EFAULT. - [High] The bpf_strcat and bpf_strncat kfuncs use the __ign suffix for the src argument, bypassing BPF verifier bounds checks and allowing an out-of-bounds kernel memory leak. - [Medium] An integer overflow in the size calculation causes bpf_strncat to silently fail to concatenate data when len is U32_MAX. - [Medium] bpf_strncat incorrectly returns -E2BIG when appending an empty string to a destination buffer that has exactly 1 byte of space left. -- --- Patch [1]: [PATCH bpf-next v3 1/2] bpf: add bpf_strcat,bpf_strncat kfunc --- commit e639d69440b707ef0e2d79161ec02f7c90946207 Author: Rong Tao <rongtao@cestc.cn> bpf: add bpf_strcat,bpf_strncat kfunc This commit introduces string concatenation kfuncs, bpf_strcat and bpf_strncat, which take the destination buffer size as a parameter for safety. It differs from the glibc library functions to ensure bounded string operations in BPF programs. > diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c > index c18f1e16edee4..e4708a4f3470a 100644 > --- a/kernel/bpf/helpers.c > +++ b/kernel/bpf/helpers.c [ ... ] > +static int __bpf_strncat(char *dst, u32 dsz, const char *src, u32 sz) > +{ > + int dlen, slen, space, copied; > + char cs; [ ... ] > + space = dsz - dlen; > + if (space <= 1 || space < min(slen, sz) + 1) > + return -E2BIG; [Severity: Medium] Does this incorrectly reject appending an empty string when the destination buffer is exactly full? If a BPF program attempts to append an empty string and space == 1 (leaving just enough room for the existing null terminator), the space <= 1 condition evaluates to true and unconditionally returns -E2BIG instead of successfully returning the original length. > + > + guard(pagefault)(); > + > + copied = strncpy_from_kernel_nofault(dst + dlen, src, > + min(space, sz + 1)); [Severity: High] Can this perform an out-of-bounds read on the source string? If a BPF program calls bpf_strncat() with a sz parameter that exactly matches the size of a source buffer lacking a null terminator, the expression sz + 1 forces strncpy_from_kernel_nofault() to read one byte past the requested length. This could trigger a spurious -EFAULT if the buffer ends at a page boundary. [Severity: Medium] Also, does the size calculation suffer from an integer overflow? If a BPF program passes U32_MAX for the sz argument to append up to the maximum possible string length, the expression sz + 1 overflows to 0 in 32-bit unsigned arithmetic. This results in strncpy_from_kernel_nofault() being called with a copy count of 0, returning success without actually appending any data. > + if (copied < 0) > + return copied; [ ... ] > +/** > + * bpf_strcat - Append non-null bytes from a source string, and null-terminate > + * the result [ ... ] > + */ > +__bpf_kfunc int bpf_strcat(char *dst, u32 dst__sz, const char *src__ign) > +{ > + return __bpf_strncat(dst, dst__sz, src__ign, XATTR_SIZE_MAX); > +} [Severity: High] Does the __ign suffix on the source string argument bypass BPF verifier bounds checks? The __ign suffix tells the verifier to ignore size constraints that normally apply to memory pointers. A BPF program could pass a pointer to a small allocated region (like a 4-byte map value) along with a large len parameter, allowing strncpy_from_kernel_nofault() to read past the buffer into adjacent kernel memory until a null byte is encountered. This would leak out-of-bounds kernel memory into the user-accessible dst buffer. > + > +/** > + * bpf_strncat - Append non-null bytes from a source string, and null-terminate > + * the result [ ... ] > + */ > +__bpf_kfunc int bpf_strncat(char *dst, u32 dst__sz, const char *src__ign, > + u32 len) > +{ > + return __bpf_strncat(dst, dst__sz, src__ign, len); > +} -- Sashiko AI review · https://sashiko.dev/#/patchset/cover.1784194024.git.rtoax@foxmail.com?part=1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpf: add bpf_strcat,bpf_strncat kfunc 2026-07-16 9:34 ` [PATCH bpf-next v3 1/2] bpf: add bpf_strcat,bpf_strncat kfunc Rong Tao 2026-07-16 9:47 ` sashiko-bot @ 2026-07-17 7:30 ` Viktor Malik 1 sibling, 0 replies; 7+ messages in thread From: Viktor Malik @ 2026-07-17 7:30 UTC (permalink / raw) To: Rong Tao, andrii, ast Cc: Rong Tao, Daniel Borkmann, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan, Yuzuki Ishiyama, open list:BPF [GENERAL] (Safe Dynamic Programs and Tools), open list, open list:KERNEL SELFTEST FRAMEWORK On 7/16/26 11:34, Rong Tao wrote: > From: Rong Tao <rongtao@cestc.cn> > > Add string concatenation kfuncs, prototype: > > int bpf_strcat(char *dst, u32 dst__sz, const char *src__ign); > int bpf_strncat(char *dst, u32 dst__sz, const char *src__ign, u32 len); Hi, while I'm still not 100% sure that we need these since the same can be achieved with bpf_probe_read_kernel_str, I do see some value in ergonomics. I have quite a few comments, though. See below. > > This differs from the glibc library functions strcat and strncat, which, > for safety reasons, require the size of the target string's memory space > as a parameter. > > Signed-off-by: Rong Tao <rongtao@cestc.cn> > --- > kernel/bpf/helpers.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 93 insertions(+) > > diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c > index c18f1e16edee..e4708a4f3470 100644 > --- a/kernel/bpf/helpers.c > +++ b/kernel/bpf/helpers.c > @@ -4195,6 +4195,97 @@ __bpf_kfunc int bpf_strncasestr(const char *s1__ign, const char *s2__ign, > return __bpf_strnstr(s1__ign, s2__ign, len, true); > } > > +static int __bpf_strncat(char *dst, u32 dsz, const char *src, u32 sz) > +{ > + int dlen, slen, space, copied; > + char cs; > + > + if (!copy_from_kernel_nofault_allowed(dst, 1) || We're not copying anything from dst, this check is not necessary. > + !copy_from_kernel_nofault_allowed(src, 1)) { This is checked by strncpy_from_kernel_nofault already, no need for a duplicate check IMHO. > + return -ERANGE; > + } > + > + dlen = bpf_strnlen(dst, dsz); Since dst is not a pointer to unsafe kernel memory, the verifier should make sure that the memory is acessible. No need for bpf_strlen here, we can just search for the null byte directly. > + if (dlen < 0) > + return dlen; > + slen = bpf_strnlen(src, sz); I don't think we need to know the size of src at all here. strncpy_from_kernel_nofault will handle it. > + if (slen < 0) > + return slen; > + > + if (dlen >= dsz || sz == 0 || dsz == 0) > + return -EINVAL; > + > + space = dsz - dlen; > + if (space <= 1 || space < min(slen, sz) + 1) > + return -E2BIG; > + > + guard(pagefault)(); strncpy_from_kernel_nofault already protects from pagefaults. > + > + copied = strncpy_from_kernel_nofault(dst + dlen, src, > + min(space, sz + 1)); Sashiko made some good points about the `sz + 1` here. Could we just use `sz` and add the null terminator manually afterwards? > + if (copied < 0) > + return copied; > + else if (copied == 0 || copied == 1) > + return dlen; > + > + /* The copied character count includes '\0'. */ > + copied--; > + > + if (copied < sz) { > + __get_kernel_nofault(&cs, src + copied, char, err_out); > + if (cs != '\0' && sz > copied) `sz > copied` is trivially true here since we're in the `copied < sz` branch. > + return -E2BIG; I don't think this is correct behavior. If this is called via bpf_strncat, then the last copied byte of src may not be '\0' but we don't want to return -E2BIG. In fact, I don't think we need the explicit bounding of bpf_strcat to XATTR_SIZE_MAX (as we do with other string kfuncs) because we are implicitly bounded by the size of dst. Viktor > + } > + > + return dlen + copied; > +err_out: > + return -EFAULT; > +} > + > +/** > + * bpf_strcat - Append non-null bytes from a source string, and null-terminate > + * the result > + * @dst: Destination string. > + * @dst__sz: Maximum bytes of @dst__ign, includes the trailing NUL. > + * @src__ign: Source string. > + * > + * Return: > + * * >=0 - Length of the concatenated string. > + * > + * * %-EINVAL - String @dst__ign is invalid. > + * * %-EFAULT - Cannot read or write one of the strings. > + * * %-E2BIG - String @src__ign is too large or the remaining space in > + * @dst__ign is too small. > + * * %-ERANGE - One of the strings is outside of kernel address space > + */ > +__bpf_kfunc int bpf_strcat(char *dst, u32 dst__sz, const char *src__ign) > +{ > + return __bpf_strncat(dst, dst__sz, src__ign, XATTR_SIZE_MAX); > +} > + > +/** > + * bpf_strncat - Append non-null bytes from a source string, and null-terminate > + * the result > + * @dst: Destination string. > + * @dst__sz: Maximum bytes of @dst__ign, includes the trailing NUL. > + * @src__ign: Source string. > + * @len: the maximum number of characters to concatenate > + * > + * Return: > + * * >=0 - Length of the concatenated string. > + * > + * * %-EINVAL - String @dst__ign is invalid. > + * * %-EFAULT - Cannot read or write one of the strings. > + * * %-E2BIG - String @src__ign is too large or the remaining space in > + * @dst__ign is too small. > + * * %-ERANGE - One of the strings is outside of kernel address space > + */ > +__bpf_kfunc int bpf_strncat(char *dst, u32 dst__sz, const char *src__ign, > + u32 len) > +{ > + return __bpf_strncat(dst, dst__sz, src__ign, len); > +} > + > #ifdef CONFIG_KEYS > /** > * bpf_lookup_user_key - lookup a key by its serial > @@ -4958,6 +5049,8 @@ BTF_ID_FLAGS(func, bpf_strstr); > BTF_ID_FLAGS(func, bpf_strcasestr); > BTF_ID_FLAGS(func, bpf_strnstr); > BTF_ID_FLAGS(func, bpf_strncasestr); > +BTF_ID_FLAGS(func, bpf_strcat); > +BTF_ID_FLAGS(func, bpf_strncat); > #if defined(CONFIG_BPF_LSM) && defined(CONFIG_CGROUPS) > BTF_ID_FLAGS(func, bpf_cgroup_read_xattr, KF_RCU) > #endif ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs [not found] <cover.1784194024.git.rtoax@foxmail.com> 2026-07-16 9:34 ` [PATCH bpf-next v3 1/2] bpf: add bpf_strcat,bpf_strncat kfunc Rong Tao @ 2026-07-16 9:34 ` Rong Tao 2026-07-16 9:49 ` sashiko-bot 2026-07-17 7:34 ` Viktor Malik 1 sibling, 2 replies; 7+ messages in thread From: Rong Tao @ 2026-07-16 9:34 UTC (permalink / raw) To: vmalik, andrii, ast Cc: Rong Tao, Daniel Borkmann, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan, Yuzuki Ishiyama, open list:BPF [GENERAL] (Safe Dynamic Programs and Tools), open list, open list:KERNEL SELFTEST FRAMEWORK From: Rong Tao <rongtao@cestc.cn> Add tests for new kfuncs bpf_strcat() and bpf_strncat(). Signed-off-by: Rong Tao <rongtao@cestc.cn> --- .../testing/selftests/bpf/prog_tests/string_kfuncs.c | 2 ++ .../selftests/bpf/progs/string_kfuncs_failure1.c | 11 +++++++++++ .../selftests/bpf/progs/string_kfuncs_failure2.c | 2 ++ .../selftests/bpf/progs/string_kfuncs_success.c | 4 ++++ 4 files changed, 19 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c index 300032a19445..460567ef622a 100644 --- a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c +++ b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c @@ -24,6 +24,8 @@ static const char * const test_cases[] = { "strcasestr", "strnstr", "strncasestr", + "strcat", + "strncat", }; void run_too_long_tests(void) diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c index bddc4e8579d2..973a6ba643d4 100644 --- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c @@ -8,6 +8,7 @@ char *user_ptr = (char *)1; char *invalid_kern_ptr = (char *)-1; +char kern_buf[32] = { "hello" }; /* * When passing userspace pointers, the error code differs based on arch: @@ -53,6 +54,8 @@ 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_strcat_null1(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), NULL); } +SEC("syscall") __retval(USER_PTR_ERR)int test_strncat_null1(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), NULL, 2); } /* 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 +82,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_strcat_user_ptr1(void *ctx) { return bpf_strcat(user_ptr, 1, "hello"); } +SEC("syscall") __retval(USER_PTR_ERR) int test_strcat_user_ptr2(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), user_ptr); } +SEC("syscall") __retval(USER_PTR_ERR) int test_strncat_user_ptr1(void *ctx) { return bpf_strncat(user_ptr, 1, "hello", 2); } +SEC("syscall") __retval(USER_PTR_ERR) int test_strncat_user_ptr2(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), user_ptr, 1); } #endif /* __TARGET_ARCH_s390 */ @@ -107,5 +114,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_strcat_pagefault1(void *ctx) { return bpf_strcat(invalid_kern_ptr, 1, "hello"); } +SEC("syscall") __retval(-EFAULT) int test_strcat_pagefault2(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), invalid_kern_ptr); } +SEC("syscall") __retval(-EFAULT) int test_strncat_pagefault1(void *ctx) { return bpf_strncat(invalid_kern_ptr, 1, "hello", 2); } +SEC("syscall") __retval(-EFAULT) int test_strncat_pagefault2(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), invalid_kern_ptr, 2); } 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 412c53b87b18..38f0a5f326b5 100644 --- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c @@ -23,5 +23,7 @@ SEC("syscall") int test_strstr_too_long(void *ctx) { return bpf_strstr(long_str, 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)); } SEC("syscall") int test_strncasestr_too_long(void *ctx) { return bpf_strncasestr(long_str, "hello", sizeof(long_str)); } +SEC("syscall") int test_strcat_too_long(void *ctx) { return bpf_strcat(long_str, sizeof(long_str), "hello"); } +SEC("syscall") int test_strncat_too_long(void *ctx) { return bpf_strncat(long_str, sizeof(long_str), "hello", 3); } char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c index f65b1226a81a..b24456ad3d43 100644 --- a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c @@ -6,6 +6,8 @@ #include "errno.h" char str[] = "hello world"; +char buf1[32] = "hello"; +char buf2[32] = "hello"; #define __test(retval) SEC("syscall") __success __retval(retval) @@ -59,5 +61,7 @@ __test(-ENOENT) int test_strncasestr_notfound1(void *ctx) { return bpf_strncases __test(-ENOENT) int test_strncasestr_notfound2(void *ctx) { return bpf_strncasestr(str, "hello", 4); } __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); } +__test(10) int test_strcat_success(void *ctx) { return bpf_strcat(buf1, sizeof(buf1), "world"); } +__test(8) int test_strncat_success(void *ctx) { return bpf_strncat(buf2, sizeof(buf2), "world", 3); } char _license[] SEC("license") = "GPL"; -- 2.55.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs 2026-07-16 9:34 ` [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs Rong Tao @ 2026-07-16 9:49 ` sashiko-bot 2026-07-17 7:34 ` Viktor Malik 1 sibling, 0 replies; 7+ messages in thread From: sashiko-bot @ 2026-07-16 9:49 UTC (permalink / raw) To: Rong Tao; +Cc: bpf Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] `__bpf_strncat` reads `sz + 1` bytes from `src` when no null terminator is found within the first `sz` bytes, violating bounded string semantics and potentially causing spurious `-EFAULT` errors. - [High] When `sz` is `U32_MAX`, the expression `sz + 1` overflows to `0` in `__bpf_strncat`, causing it to append zero bytes and silently fail to perform the concatenation. -- --- Patch [2]: [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs --- commit d6f2c6815c7c6f9bb6e7aba87e72c1ed642b70c1 Author: Rong Tao <rongtao@cestc.cn> selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs This commit adds selftests for the newly introduced bpf_strcat() and bpf_strncat() kfuncs. It includes various test cases verifying successful operations, error handling for NULL pointers and invalid memory accesses, and buffer overflow conditions. > diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c > index f65b1226a81a3..b24456ad3d43b 100644 > --- a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c > +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c [ ... ] > @@ -59,5 +61,7 @@ __test(-ENOENT) int test_strncasestr_notfound1(void *ctx) { return bpf_strncases > __test(-ENOENT) int test_strncasestr_notfound2(void *ctx) { return bpf_strncasestr(str, "hello", 4); } > __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); } > +__test(10) int test_strcat_success(void *ctx) { return bpf_strcat(buf1, sizeof(buf1), "world"); } > +__test(8) int test_strncat_success(void *ctx) { return bpf_strncat(buf2, sizeof(buf2), "world", 3); } [Severity: High] While reviewing these tests, looking at the __bpf_strncat() implementation added earlier in this series, could this result in an integer overflow if a BPF program passes U32_MAX for the len argument (sz)? kernel/bpf/helpers.c:__bpf_strncat() { ... copied = strncpy_from_kernel_nofault(dst + dlen, src, min(space, sz + 1)); ... } When sz is U32_MAX, sz + 1 overflows to 0, causing the copy routine to append zero bytes and silently fail to perform the concatenation, instead of returning an error. [Severity: High] Also looking at the same __bpf_strncat() implementation, can this cause a spurious -EFAULT if the source string exactly aligns with the end of a mapped memory page and does not contain a null terminator within the first sz bytes? Because the copy routine evaluates sz + 1, it unconditionally attempts to read one byte past the sz boundary specified by the user if no null terminator is found earlier. -- Sashiko AI review · https://sashiko.dev/#/patchset/cover.1784194024.git.rtoax@foxmail.com?part=2 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs 2026-07-16 9:34 ` [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs Rong Tao 2026-07-16 9:49 ` sashiko-bot @ 2026-07-17 7:34 ` Viktor Malik 2026-07-20 8:22 ` Rong Tao 1 sibling, 1 reply; 7+ messages in thread From: Viktor Malik @ 2026-07-17 7:34 UTC (permalink / raw) To: Rong Tao, andrii, ast Cc: Rong Tao, Daniel Borkmann, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan, Yuzuki Ishiyama, open list:BPF [GENERAL] (Safe Dynamic Programs and Tools), open list, open list:KERNEL SELFTEST FRAMEWORK On 7/16/26 11:34, Rong Tao wrote: > From: Rong Tao <rongtao@cestc.cn> > > Add tests for new kfuncs bpf_strcat() and bpf_strncat(). > > Signed-off-by: Rong Tao <rongtao@cestc.cn> > --- > .../testing/selftests/bpf/prog_tests/string_kfuncs.c | 2 ++ > .../selftests/bpf/progs/string_kfuncs_failure1.c | 11 +++++++++++ > .../selftests/bpf/progs/string_kfuncs_failure2.c | 2 ++ > .../selftests/bpf/progs/string_kfuncs_success.c | 4 ++++ > 4 files changed, 19 insertions(+) > > diff --git a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c > index 300032a19445..460567ef622a 100644 > --- a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c > +++ b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c > @@ -24,6 +24,8 @@ static const char * const test_cases[] = { > "strcasestr", > "strnstr", > "strncasestr", > + "strcat", > + "strncat", > }; > > void run_too_long_tests(void) > diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c > index bddc4e8579d2..973a6ba643d4 100644 > --- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c > +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c > @@ -8,6 +8,7 @@ > > char *user_ptr = (char *)1; > char *invalid_kern_ptr = (char *)-1; > +char kern_buf[32] = { "hello" }; > > /* > * When passing userspace pointers, the error code differs based on arch: > @@ -53,6 +54,8 @@ 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_strcat_null1(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), NULL); } > +SEC("syscall") __retval(USER_PTR_ERR)int test_strncat_null1(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), NULL, 2); } > > /* 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 +82,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_strcat_user_ptr1(void *ctx) { return bpf_strcat(user_ptr, 1, "hello"); } > +SEC("syscall") __retval(USER_PTR_ERR) int test_strcat_user_ptr2(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), user_ptr); } > +SEC("syscall") __retval(USER_PTR_ERR) int test_strncat_user_ptr1(void *ctx) { return bpf_strncat(user_ptr, 1, "hello", 2); } > +SEC("syscall") __retval(USER_PTR_ERR) int test_strncat_user_ptr2(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), user_ptr, 1); } > > #endif /* __TARGET_ARCH_s390 */ > > @@ -107,5 +114,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_strcat_pagefault1(void *ctx) { return bpf_strcat(invalid_kern_ptr, 1, "hello"); } > +SEC("syscall") __retval(-EFAULT) int test_strcat_pagefault2(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), invalid_kern_ptr); } > +SEC("syscall") __retval(-EFAULT) int test_strncat_pagefault1(void *ctx) { return bpf_strncat(invalid_kern_ptr, 1, "hello", 2); } > +SEC("syscall") __retval(-EFAULT) int test_strncat_pagefault2(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), invalid_kern_ptr, 2); } > > 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 412c53b87b18..38f0a5f326b5 100644 > --- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c > +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c > @@ -23,5 +23,7 @@ SEC("syscall") int test_strstr_too_long(void *ctx) { return bpf_strstr(long_str, > 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)); } > SEC("syscall") int test_strncasestr_too_long(void *ctx) { return bpf_strncasestr(long_str, "hello", sizeof(long_str)); } > +SEC("syscall") int test_strcat_too_long(void *ctx) { return bpf_strcat(long_str, sizeof(long_str), "hello"); } > +SEC("syscall") int test_strncat_too_long(void *ctx) { return bpf_strncat(long_str, sizeof(long_str), "hello", 3); } > > char _license[] SEC("license") = "GPL"; > diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c > index f65b1226a81a..b24456ad3d43 100644 > --- a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c > +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c > @@ -6,6 +6,8 @@ > #include "errno.h" > > char str[] = "hello world"; > +char buf1[32] = "hello"; > +char buf2[32] = "hello"; > > #define __test(retval) SEC("syscall") __success __retval(retval) > > @@ -59,5 +61,7 @@ __test(-ENOENT) int test_strncasestr_notfound1(void *ctx) { return bpf_strncases > __test(-ENOENT) int test_strncasestr_notfound2(void *ctx) { return bpf_strncasestr(str, "hello", 4); } > __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); } > +__test(10) int test_strcat_success(void *ctx) { return bpf_strcat(buf1, sizeof(buf1), "world"); } > +__test(8) int test_strncat_success(void *ctx) { return bpf_strncat(buf2, sizeof(buf2), "world", 3); } We should also add tests that verify that the string was actually copied. Viktor > > char _license[] SEC("license") = "GPL"; ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs 2026-07-17 7:34 ` Viktor Malik @ 2026-07-20 8:22 ` Rong Tao 0 siblings, 0 replies; 7+ messages in thread From: Rong Tao @ 2026-07-20 8:22 UTC (permalink / raw) To: Viktor Malik, andrii, ast Cc: Rong Tao, Daniel Borkmann, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan, Yuzuki Ishiyama, open list:BPF [GENERAL] (Safe Dynamic Programs and Tools), open list, open list:KERNEL SELFTEST FRAMEWORK On 7/17/26 15:34, Viktor Malik wrote: > On 7/16/26 11:34, Rong Tao wrote: >> From: Rong Tao <rongtao@cestc.cn> >> >> Add tests for new kfuncs bpf_strcat() and bpf_strncat(). >> >> Signed-off-by: Rong Tao <rongtao@cestc.cn> >> --- >> .../testing/selftests/bpf/prog_tests/string_kfuncs.c | 2 ++ >> .../selftests/bpf/progs/string_kfuncs_failure1.c | 11 +++++++++++ >> .../selftests/bpf/progs/string_kfuncs_failure2.c | 2 ++ >> .../selftests/bpf/progs/string_kfuncs_success.c | 4 ++++ >> 4 files changed, 19 insertions(+) >> >> diff --git a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c >> index 300032a19445..460567ef622a 100644 >> --- a/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c >> +++ b/tools/testing/selftests/bpf/prog_tests/string_kfuncs.c >> @@ -24,6 +24,8 @@ static const char * const test_cases[] = { >> "strcasestr", >> "strnstr", >> "strncasestr", >> + "strcat", >> + "strncat", >> }; >> >> void run_too_long_tests(void) >> diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c >> index bddc4e8579d2..973a6ba643d4 100644 >> --- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c >> +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c >> @@ -8,6 +8,7 @@ >> >> char *user_ptr = (char *)1; >> char *invalid_kern_ptr = (char *)-1; >> +char kern_buf[32] = { "hello" }; >> >> /* >> * When passing userspace pointers, the error code differs based on arch: >> @@ -53,6 +54,8 @@ 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_strcat_null1(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), NULL); } >> +SEC("syscall") __retval(USER_PTR_ERR)int test_strncat_null1(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), NULL, 2); } >> >> /* 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 +82,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_strcat_user_ptr1(void *ctx) { return bpf_strcat(user_ptr, 1, "hello"); } >> +SEC("syscall") __retval(USER_PTR_ERR) int test_strcat_user_ptr2(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), user_ptr); } >> +SEC("syscall") __retval(USER_PTR_ERR) int test_strncat_user_ptr1(void *ctx) { return bpf_strncat(user_ptr, 1, "hello", 2); } >> +SEC("syscall") __retval(USER_PTR_ERR) int test_strncat_user_ptr2(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), user_ptr, 1); } >> >> #endif /* __TARGET_ARCH_s390 */ >> >> @@ -107,5 +114,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_strcat_pagefault1(void *ctx) { return bpf_strcat(invalid_kern_ptr, 1, "hello"); } >> +SEC("syscall") __retval(-EFAULT) int test_strcat_pagefault2(void *ctx) { return bpf_strcat(kern_buf, sizeof(kern_buf), invalid_kern_ptr); } >> +SEC("syscall") __retval(-EFAULT) int test_strncat_pagefault1(void *ctx) { return bpf_strncat(invalid_kern_ptr, 1, "hello", 2); } >> +SEC("syscall") __retval(-EFAULT) int test_strncat_pagefault2(void *ctx) { return bpf_strncat(kern_buf, sizeof(kern_buf), invalid_kern_ptr, 2); } >> >> 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 412c53b87b18..38f0a5f326b5 100644 >> --- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c >> +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure2.c >> @@ -23,5 +23,7 @@ SEC("syscall") int test_strstr_too_long(void *ctx) { return bpf_strstr(long_str, >> 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)); } >> SEC("syscall") int test_strncasestr_too_long(void *ctx) { return bpf_strncasestr(long_str, "hello", sizeof(long_str)); } >> +SEC("syscall") int test_strcat_too_long(void *ctx) { return bpf_strcat(long_str, sizeof(long_str), "hello"); } >> +SEC("syscall") int test_strncat_too_long(void *ctx) { return bpf_strncat(long_str, sizeof(long_str), "hello", 3); } >> >> char _license[] SEC("license") = "GPL"; >> diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c >> index f65b1226a81a..b24456ad3d43 100644 >> --- a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c >> +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c >> @@ -6,6 +6,8 @@ >> #include "errno.h" >> >> char str[] = "hello world"; >> +char buf1[32] = "hello"; >> +char buf2[32] = "hello"; >> >> #define __test(retval) SEC("syscall") __success __retval(retval) >> >> @@ -59,5 +61,7 @@ __test(-ENOENT) int test_strncasestr_notfound1(void *ctx) { return bpf_strncases >> __test(-ENOENT) int test_strncasestr_notfound2(void *ctx) { return bpf_strncasestr(str, "hello", 4); } >> __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); } >> +__test(10) int test_strcat_success(void *ctx) { return bpf_strcat(buf1, sizeof(buf1), "world"); } >> +__test(8) int test_strncat_success(void *ctx) { return bpf_strncat(buf2, sizeof(buf2), "world", 3); } > We should also add tests that verify that the string was actually > copied. Thanks, i'll submit v4 ;) > > Viktor > >> >> char _license[] SEC("license") = "GPL"; ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-20 8:23 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <cover.1784194024.git.rtoax@foxmail.com>
2026-07-16 9:34 ` [PATCH bpf-next v3 1/2] bpf: add bpf_strcat,bpf_strncat kfunc Rong Tao
2026-07-16 9:47 ` sashiko-bot
2026-07-17 7:30 ` Viktor Malik
2026-07-16 9:34 ` [PATCH bpf-next v3 2/2] selftests/bpf: Test bpf_strcat,bpf_strncat kfuncs Rong Tao
2026-07-16 9:49 ` sashiko-bot
2026-07-17 7:34 ` Viktor Malik
2026-07-20 8:22 ` Rong Tao
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.