public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create()
@ 2026-04-01  0:11 Kees Cook
  2026-04-02 18:14 ` Alexei Starovoitov
  0 siblings, 1 reply; 4+ messages in thread
From: Kees Cook @ 2026-04-01  0:11 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Kees Cook, Sun Jian, Jiri Olsa, Andrii Nakryiko, Eduard Zingerman,
	Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, bpf,
	Kumar Kartikeya Dwivedi, linux-kernel, linux-hardening

BPF is the last user of the deprecated[1] strncpy() in the kernel.
Replace it with a length check via 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 the "__loader.map" 12 character string literal). The destination
attr.map_name is char[BPF_OBJ_NAME_LEN] (16 bytes) in union bpf_attr,
ultimately passed to the bpf() syscall.

The bpf(BPF_MAP_CREATE) syscall, through bpf_obj_name_cpy(), requires a
NUL terminator within this 16-byte array, rejecting names that use all 16
bytes. Valid names are therefore at most 15 characters, but this wasn't
being checked via the skel_map_create() path. Add a matching check and
refuse 16+ character strings early, as they would be refused later by
bpf_obj_name_cpy().

The attr is pre-zeroed with memset() at the top of the function, so
the last byte of attr.map_name is always NUL, meaning the memcpy()
of just the non-NUL characters from the source will always produce a
NUL-terminated destination string.

Link: https://github.com/KSPP/linux/issues/90 [1]
Suggested-by: Sun Jian <sun.jian.kdev@gmail.com>
Signed-off-by: Kees Cook <kees@kernel.org>
---
 v4: Reformat commit log slightly, confirm last user of strnlen in -next
 v3: https://lore.kernel.org/lkml/20260324161605.make.168-kees@kernel.org/
 v2: https://lore.kernel.org/lkml/20260324053036.it.906-kees@kernel.org/
 v1: https://lore.kernel.org/lkml/20260324040535.work.851-kees@kernel.org/
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: sun jian <sun.jian.kdev@gmail.com>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Eduard Zingerman <eddyz87@gmail.com>
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: <bpf@vger.kernel.org>
---
 tools/lib/bpf/skel_internal.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
index 6a8f5c7a02eb..2d38c387f43c 100644
--- a/tools/lib/bpf/skel_internal.h
+++ b/tools/lib/bpf/skel_internal.h
@@ -236,6 +236,7 @@ static inline int skel_map_create(enum bpf_map_type map_type,
 {
 	const size_t attr_sz = offsetofend(union bpf_attr, excl_prog_hash_size);
 	union bpf_attr attr;
+	size_t map_name_len;
 
 	memset(&attr, 0, attr_sz);
 
@@ -243,7 +244,12 @@ 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));
+	/* attr.map_name must be NUL-terminated, like bpf_obj_name_cpy() */
+	map_name_len = strnlen(map_name, sizeof(attr.map_name));
+	if (map_name_len == sizeof(attr.map_name))
+		return -EINVAL;
+	memcpy(attr.map_name, map_name, map_name_len);
+
 	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 v4] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create()
  2026-04-01  0:11 [PATCH v4] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create() Kees Cook
@ 2026-04-02 18:14 ` Alexei Starovoitov
  2026-04-03 15:54   ` Kees Cook
  0 siblings, 1 reply; 4+ messages in thread
From: Alexei Starovoitov @ 2026-04-02 18:14 UTC (permalink / raw)
  To: Kees Cook
  Cc: Alexei Starovoitov, Sun Jian, Jiri Olsa, Andrii Nakryiko,
	Eduard Zingerman, Daniel Borkmann, Martin KaFai Lau, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
	Hao Luo, bpf, Kumar Kartikeya Dwivedi, LKML, linux-hardening

On Tue, Mar 31, 2026 at 5:11 PM Kees Cook <kees@kernel.org> wrote:
>
> BPF is the last user of the deprecated[1] strncpy() in the kernel.
> Replace it with a length check via 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 the "__loader.map" 12 character string literal). The destination
> attr.map_name is char[BPF_OBJ_NAME_LEN] (16 bytes) in union bpf_attr,
> ultimately passed to the bpf() syscall.
>
> The bpf(BPF_MAP_CREATE) syscall, through bpf_obj_name_cpy(), requires a
> NUL terminator within this 16-byte array, rejecting names that use all 16
> bytes. Valid names are therefore at most 15 characters, but this wasn't
> being checked via the skel_map_create() path. Add a matching check and
> refuse 16+ character strings early, as they would be refused later by
> bpf_obj_name_cpy().
>
> The attr is pre-zeroed with memset() at the top of the function, so
> the last byte of attr.map_name is always NUL, meaning the memcpy()
> of just the non-NUL characters from the source will always produce a
> NUL-terminated destination string.
>
> Link: https://github.com/KSPP/linux/issues/90 [1]
> Suggested-by: Sun Jian <sun.jian.kdev@gmail.com>
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
>  v4: Reformat commit log slightly, confirm last user of strnlen in -next
>  v3: https://lore.kernel.org/lkml/20260324161605.make.168-kees@kernel.org/
>  v2: https://lore.kernel.org/lkml/20260324053036.it.906-kees@kernel.org/
>  v1: https://lore.kernel.org/lkml/20260324040535.work.851-kees@kernel.org/
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Cc: sun jian <sun.jian.kdev@gmail.com>
> Cc: Andrii Nakryiko <andrii@kernel.org>
> Cc: Eduard Zingerman <eddyz87@gmail.com>
> 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: <bpf@vger.kernel.org>
> ---
>  tools/lib/bpf/skel_internal.h | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
> index 6a8f5c7a02eb..2d38c387f43c 100644
> --- a/tools/lib/bpf/skel_internal.h
> +++ b/tools/lib/bpf/skel_internal.h
> @@ -236,6 +236,7 @@ static inline int skel_map_create(enum bpf_map_type map_type,
>  {
>         const size_t attr_sz = offsetofend(union bpf_attr, excl_prog_hash_size);
>         union bpf_attr attr;
> +       size_t map_name_len;
>
>         memset(&attr, 0, attr_sz);
>
> @@ -243,7 +244,12 @@ 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));
> +       /* attr.map_name must be NUL-terminated, like bpf_obj_name_cpy() */
> +       map_name_len = strnlen(map_name, sizeof(attr.map_name));
> +       if (map_name_len == sizeof(attr.map_name))
> +               return -EINVAL;
> +       memcpy(attr.map_name, map_name, map_name_len);

this is plain ugly and inefficient.
Just #ifdef kernel and use strscpy in that branch.

pw-bot: cr

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create()
  2026-04-02 18:14 ` Alexei Starovoitov
@ 2026-04-03 15:54   ` Kees Cook
  2026-04-03 16:16     ` Alexei Starovoitov
  0 siblings, 1 reply; 4+ messages in thread
From: Kees Cook @ 2026-04-03 15:54 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Alexei Starovoitov, Sun Jian, Jiri Olsa, Andrii Nakryiko,
	Eduard Zingerman, Daniel Borkmann, Martin KaFai Lau, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
	Hao Luo, bpf, Kumar Kartikeya Dwivedi, LKML, linux-hardening

On Thu, Apr 02, 2026 at 11:14:58AM -0700, Alexei Starovoitov wrote:
> On Tue, Mar 31, 2026 at 5:11 PM Kees Cook <kees@kernel.org> wrote:
> >
> > BPF is the last user of the deprecated[1] strncpy() in the kernel.
> > Replace it with a length check via 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 the "__loader.map" 12 character string literal). The destination
> > attr.map_name is char[BPF_OBJ_NAME_LEN] (16 bytes) in union bpf_attr,
> > ultimately passed to the bpf() syscall.
> >
> > The bpf(BPF_MAP_CREATE) syscall, through bpf_obj_name_cpy(), requires a
> > NUL terminator within this 16-byte array, rejecting names that use all 16
> > bytes. Valid names are therefore at most 15 characters, but this wasn't
> > being checked via the skel_map_create() path. Add a matching check and
> > refuse 16+ character strings early, as they would be refused later by
> > bpf_obj_name_cpy().
> >
> > The attr is pre-zeroed with memset() at the top of the function, so
> > the last byte of attr.map_name is always NUL, meaning the memcpy()
> > of just the non-NUL characters from the source will always produce a
> > NUL-terminated destination string.
> >
> > Link: https://github.com/KSPP/linux/issues/90 [1]
> > Suggested-by: Sun Jian <sun.jian.kdev@gmail.com>
> > Signed-off-by: Kees Cook <kees@kernel.org>
> > ---
> >  v4: Reformat commit log slightly, confirm last user of strnlen in -next
> >  v3: https://lore.kernel.org/lkml/20260324161605.make.168-kees@kernel.org/
> >  v2: https://lore.kernel.org/lkml/20260324053036.it.906-kees@kernel.org/
> >  v1: https://lore.kernel.org/lkml/20260324040535.work.851-kees@kernel.org/
> > Cc: Alexei Starovoitov <ast@kernel.org>
> > Cc: Jiri Olsa <jolsa@kernel.org>
> > Cc: sun jian <sun.jian.kdev@gmail.com>
> > Cc: Andrii Nakryiko <andrii@kernel.org>
> > Cc: Eduard Zingerman <eddyz87@gmail.com>
> > 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: <bpf@vger.kernel.org>
> > ---
> >  tools/lib/bpf/skel_internal.h | 8 +++++++-
> >  1 file changed, 7 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
> > index 6a8f5c7a02eb..2d38c387f43c 100644
> > --- a/tools/lib/bpf/skel_internal.h
> > +++ b/tools/lib/bpf/skel_internal.h
> > @@ -236,6 +236,7 @@ static inline int skel_map_create(enum bpf_map_type map_type,
> >  {
> >         const size_t attr_sz = offsetofend(union bpf_attr, excl_prog_hash_size);
> >         union bpf_attr attr;
> > +       size_t map_name_len;
> >
> >         memset(&attr, 0, attr_sz);
> >
> > @@ -243,7 +244,12 @@ 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));
> > +       /* attr.map_name must be NUL-terminated, like bpf_obj_name_cpy() */
> > +       map_name_len = strnlen(map_name, sizeof(attr.map_name));
> > +       if (map_name_len == sizeof(attr.map_name))
> > +               return -EINVAL;
> > +       memcpy(attr.map_name, map_name, map_name_len);
> 
> this is plain ugly and inefficient.
> Just #ifdef kernel and use strscpy in that branch.

I think you're asking for:

#ifdef __KERNEL__
	if (strscpy(attr.map_name, map_name) < 0)
		return -EINVAL;
#else
	strncpy(attr.map_name, map_name, sizeof(attr.map_name));
#endif

Is that right?

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create()
  2026-04-03 15:54   ` Kees Cook
@ 2026-04-03 16:16     ` Alexei Starovoitov
  0 siblings, 0 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2026-04-03 16:16 UTC (permalink / raw)
  To: Kees Cook
  Cc: Alexei Starovoitov, Sun Jian, Jiri Olsa, Andrii Nakryiko,
	Eduard Zingerman, Daniel Borkmann, Martin KaFai Lau, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
	Hao Luo, bpf, Kumar Kartikeya Dwivedi, LKML, linux-hardening

On Fri, Apr 3, 2026 at 8:54 AM Kees Cook <kees@kernel.org> wrote:
> > > -       strncpy(attr.map_name, map_name, sizeof(attr.map_name));
> > > +       /* attr.map_name must be NUL-terminated, like bpf_obj_name_cpy() */
> > > +       map_name_len = strnlen(map_name, sizeof(attr.map_name));
> > > +       if (map_name_len == sizeof(attr.map_name))
> > > +               return -EINVAL;
> > > +       memcpy(attr.map_name, map_name, map_name_len);
> >
> > this is plain ugly and inefficient.
> > Just #ifdef kernel and use strscpy in that branch.
>
> I think you're asking for:
>
> #ifdef __KERNEL__
>         if (strscpy(attr.map_name, map_name) < 0)
>                 return -EINVAL;
> #else
>         strncpy(attr.map_name, map_name, sizeof(attr.map_name));
> #endif
>
> Is that right?

yes.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-04-03 16:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-01  0:11 [PATCH v4] libbpf: Replace strncpy() with strnlen()+memcpy() in skel_map_create() Kees Cook
2026-04-02 18:14 ` Alexei Starovoitov
2026-04-03 15:54   ` Kees Cook
2026-04-03 16:16     ` Alexei Starovoitov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox