* [PATCH v2] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create()
@ 2026-03-24 5:30 Kees Cook
2026-03-24 9:21 ` Jiri Olsa
2026-03-24 14:50 ` Alexei Starovoitov
0 siblings, 2 replies; 4+ messages in thread
From: Kees Cook @ 2026-03-24 5:30 UTC (permalink / raw)
To: Andrii Nakryiko
Cc: Kees Cook, Eduard Zingerman, Alexei Starovoitov, Daniel Borkmann,
Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa, bpf,
linux-kernel, linux-hardening
Replace the deprecated[1] strncpy() with strnlen() on the source
followed by memcpy(). Normally strscpy() would be used in this case,
but skel_internal.h is shared between kernel and userspace tools, and
strscpy() is not available in the userspace build context.
The source map_name is a NUL-terminated C string (the only caller
passes a 12 character string literal). The destination attr.map_name is
char[BPF_OBJ_NAME_LEN] (16 bytes) in union bpf_attr, passed to the bpf()
syscall. The kernel's bpf_obj_name_cpy() requires a NUL terminator within
the 16-byte field, rejecting names that use all 16 bytes. Valid names
are therefore at most 15 characters.
The attr is pre-zeroed with memset() at the top of the function,
so the byte at position 15 is always NUL. The copy is bounded to
sizeof(attr.map_name) - 1 (15 bytes) to guarantee NUL-termination is
preserved. This is safe because the kernel would reject a 16-byte
unterminated name anyway, and the only in-tree caller passes
"__loader.map" (12 characters).
While the original strncpy() would have copied a full 16 bytes from an
overlong name (producing an unterminated field that the syscall rejects),
but this shouldn't be a reachable state. Forcing truncation to 15 bytes,
however, seemed to induce a (unrelated?) BPF selftest failure:
https://github.com/kernel-patches/bpf/actions/runs/23472955268/job/68300440546
Allow the literal to exceed 15 characters and exactly reproduce the
original strncpy() behavior (potentially lacking a NUL termination).
Link: https://github.com/KSPP/linux/issues/90 [1]
Signed-off-by: Kees Cook <kees@kernel.org>
---
v2: don't force truncation
v1: https://lore.kernel.org/lkml/20260324040535.work.851-kees@kernel.org/
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Eduard Zingerman <eddyz87@gmail.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Martin KaFai Lau <martin.lau@linux.dev>
Cc: Song Liu <song@kernel.org>
Cc: Yonghong Song <yonghong.song@linux.dev>
Cc: John Fastabend <john.fastabend@gmail.com>
Cc: KP Singh <kpsingh@kernel.org>
Cc: Stanislav Fomichev <sdf@fomichev.me>
Cc: Hao Luo <haoluo@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: <bpf@vger.kernel.org>
---
tools/lib/bpf/skel_internal.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
index 6a8f5c7a02eb..8702d6612978 100644
--- a/tools/lib/bpf/skel_internal.h
+++ b/tools/lib/bpf/skel_internal.h
@@ -243,7 +243,8 @@ static inline int skel_map_create(enum bpf_map_type map_type,
attr.excl_prog_hash = (unsigned long) excl_prog_hash;
attr.excl_prog_hash_size = excl_prog_hash_sz;
- strncpy(attr.map_name, map_name, sizeof(attr.map_name));
+ memcpy(attr.map_name, map_name,
+ strnlen(map_name, sizeof(attr.map_name)));
attr.key_size = key_size;
attr.value_size = value_size;
attr.max_entries = max_entries;
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create()
2026-03-24 5:30 [PATCH v2] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create() Kees Cook
@ 2026-03-24 9:21 ` Jiri Olsa
2026-03-24 15:26 ` Kees Cook
2026-03-24 14:50 ` Alexei Starovoitov
1 sibling, 1 reply; 4+ messages in thread
From: Jiri Olsa @ 2026-03-24 9:21 UTC (permalink / raw)
To: Kees Cook
Cc: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, bpf,
linux-kernel, linux-hardening
On Mon, Mar 23, 2026 at 10:30:37PM -0700, Kees Cook wrote:
> Replace the deprecated[1] strncpy() with strnlen() on the source
> followed by memcpy(). Normally strscpy() would be used in this case,
> but skel_internal.h is shared between kernel and userspace tools, and
> strscpy() is not available in the userspace build context.
>
> The source map_name is a NUL-terminated C string (the only caller
> passes a 12 character string literal). The destination attr.map_name is
> char[BPF_OBJ_NAME_LEN] (16 bytes) in union bpf_attr, passed to the bpf()
> syscall. The kernel's bpf_obj_name_cpy() requires a NUL terminator within
> the 16-byte field, rejecting names that use all 16 bytes. Valid names
> are therefore at most 15 characters.
>
> The attr is pre-zeroed with memset() at the top of the function,
> so the byte at position 15 is always NUL. The copy is bounded to
> sizeof(attr.map_name) - 1 (15 bytes) to guarantee NUL-termination is
hm, but this version no longer does that, right?
jirka
> preserved. This is safe because the kernel would reject a 16-byte
> unterminated name anyway, and the only in-tree caller passes
> "__loader.map" (12 characters).
>
> While the original strncpy() would have copied a full 16 bytes from an
> overlong name (producing an unterminated field that the syscall rejects),
> but this shouldn't be a reachable state. Forcing truncation to 15 bytes,
> however, seemed to induce a (unrelated?) BPF selftest failure:
> https://github.com/kernel-patches/bpf/actions/runs/23472955268/job/68300440546
>
> Allow the literal to exceed 15 characters and exactly reproduce the
> original strncpy() behavior (potentially lacking a NUL termination).
>
> Link: https://github.com/KSPP/linux/issues/90 [1]
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
> v2: don't force truncation
> v1: https://lore.kernel.org/lkml/20260324040535.work.851-kees@kernel.org/
> Cc: Andrii Nakryiko <andrii@kernel.org>
> Cc: Eduard Zingerman <eddyz87@gmail.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Martin KaFai Lau <martin.lau@linux.dev>
> Cc: Song Liu <song@kernel.org>
> Cc: Yonghong Song <yonghong.song@linux.dev>
> Cc: John Fastabend <john.fastabend@gmail.com>
> Cc: KP Singh <kpsingh@kernel.org>
> Cc: Stanislav Fomichev <sdf@fomichev.me>
> Cc: Hao Luo <haoluo@google.com>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Cc: <bpf@vger.kernel.org>
> ---
> tools/lib/bpf/skel_internal.h | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
> index 6a8f5c7a02eb..8702d6612978 100644
> --- a/tools/lib/bpf/skel_internal.h
> +++ b/tools/lib/bpf/skel_internal.h
> @@ -243,7 +243,8 @@ static inline int skel_map_create(enum bpf_map_type map_type,
> attr.excl_prog_hash = (unsigned long) excl_prog_hash;
> attr.excl_prog_hash_size = excl_prog_hash_sz;
>
> - strncpy(attr.map_name, map_name, sizeof(attr.map_name));
> + memcpy(attr.map_name, map_name,
> + strnlen(map_name, sizeof(attr.map_name)));
> attr.key_size = key_size;
> attr.value_size = value_size;
> attr.max_entries = max_entries;
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create()
2026-03-24 5:30 [PATCH v2] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create() Kees Cook
2026-03-24 9:21 ` Jiri Olsa
@ 2026-03-24 14:50 ` Alexei Starovoitov
1 sibling, 0 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2026-03-24 14:50 UTC (permalink / raw)
To: Kees Cook
Cc: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
bpf, LKML, linux-hardening
On Mon, Mar 23, 2026 at 10:30 PM Kees Cook <kees@kernel.org> wrote:
>
> Replace the deprecated[1] strncpy() with strnlen() on the source
> followed by memcpy(). Normally strscpy() would be used in this case,
> but skel_internal.h is shared between kernel and userspace tools, and
> strscpy() is not available in the userspace build context.
>
> The source map_name is a NUL-terminated C string (the only caller
> passes a 12 character string literal). The destination attr.map_name is
> char[BPF_OBJ_NAME_LEN] (16 bytes) in union bpf_attr, passed to the bpf()
> syscall. The kernel's bpf_obj_name_cpy() requires a NUL terminator within
> the 16-byte field, rejecting names that use all 16 bytes. Valid names
> are therefore at most 15 characters.
>
> The attr is pre-zeroed with memset() at the top of the function,
> so the byte at position 15 is always NUL. The copy is bounded to
> sizeof(attr.map_name) - 1 (15 bytes) to guarantee NUL-termination is
> preserved. This is safe because the kernel would reject a 16-byte
> unterminated name anyway, and the only in-tree caller passes
> "__loader.map" (12 characters).
>
> While the original strncpy() would have copied a full 16 bytes from an
> overlong name (producing an unterminated field that the syscall rejects),
> but this shouldn't be a reachable state. Forcing truncation to 15 bytes,
> however, seemed to induce a (unrelated?) BPF selftest failure:
> https://github.com/kernel-patches/bpf/actions/runs/23472955268/job/68300440546
>
> Allow the literal to exceed 15 characters and exactly reproduce the
> original strncpy() behavior (potentially lacking a NUL termination).
>
> Link: https://github.com/KSPP/linux/issues/90 [1]
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
> v2: don't force truncation
> v1: https://lore.kernel.org/lkml/20260324040535.work.851-kees@kernel.org/
> Cc: Andrii Nakryiko <andrii@kernel.org>
> Cc: Eduard Zingerman <eddyz87@gmail.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Martin KaFai Lau <martin.lau@linux.dev>
> Cc: Song Liu <song@kernel.org>
> Cc: Yonghong Song <yonghong.song@linux.dev>
> Cc: John Fastabend <john.fastabend@gmail.com>
> Cc: KP Singh <kpsingh@kernel.org>
> Cc: Stanislav Fomichev <sdf@fomichev.me>
> Cc: Hao Luo <haoluo@google.com>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Cc: <bpf@vger.kernel.org>
> ---
> tools/lib/bpf/skel_internal.h | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
> index 6a8f5c7a02eb..8702d6612978 100644
> --- a/tools/lib/bpf/skel_internal.h
> +++ b/tools/lib/bpf/skel_internal.h
> @@ -243,7 +243,8 @@ static inline int skel_map_create(enum bpf_map_type map_type,
> attr.excl_prog_hash = (unsigned long) excl_prog_hash;
> attr.excl_prog_hash_size = excl_prog_hash_sz;
>
> - strncpy(attr.map_name, map_name, sizeof(attr.map_name));
> + memcpy(attr.map_name, map_name,
> + strnlen(map_name, sizeof(attr.map_name)));
wont-fix.
pw-bot: cr
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create()
2026-03-24 9:21 ` Jiri Olsa
@ 2026-03-24 15:26 ` Kees Cook
0 siblings, 0 replies; 4+ messages in thread
From: Kees Cook @ 2026-03-24 15:26 UTC (permalink / raw)
To: Jiri Olsa
Cc: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, bpf,
linux-kernel, linux-hardening
On March 24, 2026 2:21:58 AM PDT, Jiri Olsa <olsajiri@gmail.com> wrote:
>On Mon, Mar 23, 2026 at 10:30:37PM -0700, Kees Cook wrote:
>> Replace the deprecated[1] strncpy() with strnlen() on the source
>> followed by memcpy(). Normally strscpy() would be used in this case,
>> but skel_internal.h is shared between kernel and userspace tools, and
>> strscpy() is not available in the userspace build context.
>>
>> The source map_name is a NUL-terminated C string (the only caller
>> passes a 12 character string literal). The destination attr.map_name is
>> char[BPF_OBJ_NAME_LEN] (16 bytes) in union bpf_attr, passed to the bpf()
>> syscall. The kernel's bpf_obj_name_cpy() requires a NUL terminator within
>> the 16-byte field, rejecting names that use all 16 bytes. Valid names
>> are therefore at most 15 characters.
>>
>> The attr is pre-zeroed with memset() at the top of the function,
>> so the byte at position 15 is always NUL. The copy is bounded to
>> sizeof(attr.map_name) - 1 (15 bytes) to guarantee NUL-termination is
>
>hm, but this version no longer does that, right?
Arg. Yes, correct. I'll fix the commit log for v3. And yes, the bpf test suite reported that v2 shows no test failures any more.
(Why does this need an unterminated string internally here when the syscall refuses to build one?)
--
Kees Cook
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-03-24 15:26 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-24 5:30 [PATCH v2] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create() Kees Cook
2026-03-24 9:21 ` Jiri Olsa
2026-03-24 15:26 ` Kees Cook
2026-03-24 14:50 ` Alexei Starovoitov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox