[LTP] [PATCH] syscalls/bpf: zero-initialize bpf_attr including padding bits

Jan Stancek jstancek@redhat.com
Thu Feb 6 15:34:47 CET 2025


On Thu, Feb 6, 2025 at 3:08 PM Cyril Hrubis <chrubis@suse.cz> wrote:
>
> Hi!
> > However kernel bpf syscall checks that all unused fields for a command
> > are set to zero in CHECK_ATTR() macro, which causes tests to fail with
> > EINVAL.
> >
> > Signed-off-by: Jan Stancek <jstancek@redhat.com>
> > ---
> >  testcases/kernel/syscalls/bpf/bpf_common.c | 32 ++++++++++++----------
> >  1 file changed, 18 insertions(+), 14 deletions(-)
> >
> > diff --git a/testcases/kernel/syscalls/bpf/bpf_common.c b/testcases/kernel/syscalls/bpf/bpf_common.c
> > index 95b5bc12eaa4..d765c4e32936 100644
> > --- a/testcases/kernel/syscalls/bpf/bpf_common.c
> > +++ b/testcases/kernel/syscalls/bpf/bpf_common.c
> > @@ -49,13 +49,14 @@ int bpf_map_create(union bpf_attr *const attr)
> >
> >  int bpf_map_array_create(const uint32_t max_entries)
> >  {
> > -     union bpf_attr map_attr = {
> > -             .map_type = BPF_MAP_TYPE_ARRAY,
> > -             .key_size = 4,
> > -             .value_size = 8,
> > -             .max_entries = max_entries,
> > -             .map_flags = 0
> > -     };
> > +     /* zero-initialize entire struct including padding bits */
> > +     union bpf_attr map_attr = {};
> > +
> > +     map_attr.map_type = BPF_MAP_TYPE_ARRAY;
> > +     map_attr.key_size = 4;
> > +     map_attr.value_size = 8;
> > +     map_attr.max_entries = max_entries;
> > +     map_attr.map_flags = 0;
>
> I had a closer look here, the map_attr is an union with anonymous
> structures and I suppose that the problem here is that the padding after
> the union is no longer cleared and that there have been some new fields
> added, at least compared to the lapi fallback structures we have and we
> possibly pass random mess in flags.

It's not just padding, some fields (from other structs) are also not
initialized:

void bpf_map_array_get(const int map_fd,
                       const uint32_t *const array_indx,
                       uint64_t *const array_val)
{
        union bpf_attr elem_attr = {
                .map_fd = map_fd,
                .key = ptr_to_u64(array_indx),
                .value = ptr_to_u64(array_val),
                .flags = 0
        };

        printf("should be zero? %u\n", elem_attr.func_info_cnt);

and I get:
should be zero? 4202093

func_info_cnt is at offset 88, which is far away from ones we
initialized explicitly:

        struct {
                uint32_t           map_fd;             /*     0     4 */

                /* XXX 4 bytes hole, try to pack */

                uint64_t           key
__attribute__((__aligned__(8))); /*     8     8 */
                union {
                        uint64_t   value
__attribute__((__aligned__(8))); /*    16     8 */
                        uint64_t   next_key
__attribute__((__aligned__(8))); /*    16     8 */
                } __attribute__((__aligned__(8)));     /*    16     8 */
                uint64_t           flags;              /*    24     8 */
        } __attribute__((__aligned__(8)))
__attribute__((__aligned__(8)));             /*     0    32 */

>
> Maybe slightly better version would be:
>
> diff --git a/testcases/kernel/syscalls/bpf/bpf_common.c b/testcases/kernel/syscalls/bpf/bpf_common.c
> index 95b5bc12e..a8289e106 100644
> --- a/testcases/kernel/syscalls/bpf/bpf_common.c
> +++ b/testcases/kernel/syscalls/bpf/bpf_common.c
> @@ -49,7 +49,9 @@ int bpf_map_create(union bpf_attr *const attr)
>
>  int bpf_map_array_create(const uint32_t max_entries)
>  {
> -       union bpf_attr map_attr = {
> +       union bpf_attr map_attr = {};
> +
> +       map_attr = (union bpf_attr) {
>                 .map_type = BPF_MAP_TYPE_ARRAY,
>                 .key_size = 4,
>                 .value_size = 8,
>
>
> --
> Cyril Hrubis
> chrubis@suse.cz
>



More information about the ltp mailing list