diff mbox series

[bpf-next,1/2] bpf: fix setting return values for htab batch ops

Message ID 20230717114307.46124-2-aspsk@isovalent.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series fix setting return values for htab batch ops and docs | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1354 this patch: 1354
netdev/cc_maintainers success CCed 13 of 13 maintainers
netdev/build_clang success Errors and warnings before: 1365 this patch: 1365
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 1377 this patch: 1377
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 26 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-15 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-6 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with llvm-16

Commit Message

Anton Protopopov July 17, 2023, 11:43 a.m. UTC
The map_lookup{,_and_delete}_batch operations are expected to set the
output parameter, counter, to the number of elements successfully copied
to the user space. This is also expected to be true if an error is
returned and the errno is set to a value other than EFAULT. The current
implementation can return -EINVAL without setting the counter to zero, so
some userspace programs may confuse this with a [partially] successful
operation. Move code which sets the counter to zero to the top of the
function so that we always return a correct value.

Fixes: 057996380a42 ("bpf: Add batch ops to all htab bpf map")
Signed-off-by: Anton Protopopov <aspsk@isovalent.com>
---
 kernel/bpf/hashtab.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

Comments

Alexei Starovoitov July 19, 2023, 12:52 a.m. UTC | #1
On Mon, Jul 17, 2023 at 4:42 AM Anton Protopopov <aspsk@isovalent.com> wrote:
>
> The map_lookup{,_and_delete}_batch operations are expected to set the
> output parameter, counter, to the number of elements successfully copied
> to the user space. This is also expected to be true if an error is
> returned and the errno is set to a value other than EFAULT. The current
> implementation can return -EINVAL without setting the counter to zero, so
> some userspace programs may confuse this with a [partially] successful
> operation. Move code which sets the counter to zero to the top of the
> function so that we always return a correct value.
>
> Fixes: 057996380a42 ("bpf: Add batch ops to all htab bpf map")
> Signed-off-by: Anton Protopopov <aspsk@isovalent.com>
> ---
>  kernel/bpf/hashtab.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
> index a8c7e1c5abfa..fa8e3f1e1724 100644
> --- a/kernel/bpf/hashtab.c
> +++ b/kernel/bpf/hashtab.c
> @@ -1692,6 +1692,13 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
>         struct bucket *b;
>         int ret = 0;
>
> +       max_count = attr->batch.count;
> +       if (!max_count)
> +               return 0;
> +
> +       if (put_user(0, &uattr->batch.count))
> +               return -EFAULT;
> +
>         elem_map_flags = attr->batch.elem_flags;
>         if ((elem_map_flags & ~BPF_F_LOCK) ||
>             ((elem_map_flags & BPF_F_LOCK) && !btf_record_has_field(map->record, BPF_SPIN_LOCK)))
> @@ -1701,13 +1708,6 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
>         if (map_flags)
>                 return -EINVAL;
>
> -       max_count = attr->batch.count;
> -       if (!max_count)
> -               return 0;
> -
> -       if (put_user(0, &uattr->batch.count))
> -               return -EFAULT;
> -

I hear your concern, but I don't think it's a good idea
to return 0 when flags were incorrect.
That will cause more suprises to user space.
I think the code is fine as-is.
Anton Protopopov July 19, 2023, 7:09 a.m. UTC | #2
On Tue, Jul 18, 2023 at 05:52:38PM -0700, Alexei Starovoitov wrote:
> On Mon, Jul 17, 2023 at 4:42 AM Anton Protopopov <aspsk@isovalent.com> wrote:
> >
> > The map_lookup{,_and_delete}_batch operations are expected to set the
> > output parameter, counter, to the number of elements successfully copied
> > to the user space. This is also expected to be true if an error is
> > returned and the errno is set to a value other than EFAULT. The current
> > implementation can return -EINVAL without setting the counter to zero, so
> > some userspace programs may confuse this with a [partially] successful
> > operation. Move code which sets the counter to zero to the top of the
> > function so that we always return a correct value.
> >
> > Fixes: 057996380a42 ("bpf: Add batch ops to all htab bpf map")
> > Signed-off-by: Anton Protopopov <aspsk@isovalent.com>
> > ---
> >  kernel/bpf/hashtab.c | 14 +++++++-------
> >  1 file changed, 7 insertions(+), 7 deletions(-)
> >
> > diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
> > index a8c7e1c5abfa..fa8e3f1e1724 100644
> > --- a/kernel/bpf/hashtab.c
> > +++ b/kernel/bpf/hashtab.c
> > @@ -1692,6 +1692,13 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
> >         struct bucket *b;
> >         int ret = 0;
> >
> > +       max_count = attr->batch.count;
> > +       if (!max_count)
> > +               return 0;
> > +
> > +       if (put_user(0, &uattr->batch.count))
> > +               return -EFAULT;
> > +
> >         elem_map_flags = attr->batch.elem_flags;
> >         if ((elem_map_flags & ~BPF_F_LOCK) ||
> >             ((elem_map_flags & BPF_F_LOCK) && !btf_record_has_field(map->record, BPF_SPIN_LOCK)))
> > @@ -1701,13 +1708,6 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
> >         if (map_flags)
> >                 return -EINVAL;
> >
> > -       max_count = attr->batch.count;
> > -       if (!max_count)
> > -               return 0;
> > -
> > -       if (put_user(0, &uattr->batch.count))
> > -               return -EFAULT;
> > -
> 
> I hear your concern, but I don't think it's a good idea
> to return 0 when flags were incorrect.
> That will cause more suprises to user space.
> I think the code is fine as-is.

Yes, thanks, this makes sense. And actually we can do both:

   max_count = attr->batch.count;
   put_user(0, &uattr->batch.count);
   /* check flags */
   if (!max_count)
           return 0;

This way we always set the userspace counter to a correct value
and also check flags in the right place.
Alexei Starovoitov July 19, 2023, 4:28 p.m. UTC | #3
On Wed, Jul 19, 2023 at 12:07 AM Anton Protopopov <aspsk@isovalent.com> wrote:
>
> On Tue, Jul 18, 2023 at 05:52:38PM -0700, Alexei Starovoitov wrote:
> > On Mon, Jul 17, 2023 at 4:42 AM Anton Protopopov <aspsk@isovalent.com> wrote:
> > >
> > > The map_lookup{,_and_delete}_batch operations are expected to set the
> > > output parameter, counter, to the number of elements successfully copied
> > > to the user space. This is also expected to be true if an error is
> > > returned and the errno is set to a value other than EFAULT. The current
> > > implementation can return -EINVAL without setting the counter to zero, so
> > > some userspace programs may confuse this with a [partially] successful
> > > operation. Move code which sets the counter to zero to the top of the
> > > function so that we always return a correct value.
> > >
> > > Fixes: 057996380a42 ("bpf: Add batch ops to all htab bpf map")
> > > Signed-off-by: Anton Protopopov <aspsk@isovalent.com>
> > > ---
> > >  kernel/bpf/hashtab.c | 14 +++++++-------
> > >  1 file changed, 7 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
> > > index a8c7e1c5abfa..fa8e3f1e1724 100644
> > > --- a/kernel/bpf/hashtab.c
> > > +++ b/kernel/bpf/hashtab.c
> > > @@ -1692,6 +1692,13 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
> > >         struct bucket *b;
> > >         int ret = 0;
> > >
> > > +       max_count = attr->batch.count;
> > > +       if (!max_count)
> > > +               return 0;
> > > +
> > > +       if (put_user(0, &uattr->batch.count))
> > > +               return -EFAULT;
> > > +
> > >         elem_map_flags = attr->batch.elem_flags;
> > >         if ((elem_map_flags & ~BPF_F_LOCK) ||
> > >             ((elem_map_flags & BPF_F_LOCK) && !btf_record_has_field(map->record, BPF_SPIN_LOCK)))
> > > @@ -1701,13 +1708,6 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
> > >         if (map_flags)
> > >                 return -EINVAL;
> > >
> > > -       max_count = attr->batch.count;
> > > -       if (!max_count)
> > > -               return 0;
> > > -
> > > -       if (put_user(0, &uattr->batch.count))
> > > -               return -EFAULT;
> > > -
> >
> > I hear your concern, but I don't think it's a good idea
> > to return 0 when flags were incorrect.
> > That will cause more suprises to user space.
> > I think the code is fine as-is.
>
> Yes, thanks, this makes sense. And actually we can do both:
>
>    max_count = attr->batch.count;
>    put_user(0, &uattr->batch.count);
>    /* check flags */
>    if (!max_count)
>            return 0;
>
> This way we always set the userspace counter to a correct value
> and also check flags in the right place.

Looks too convoluted to me.
I think concerns over user space always assuming batch.count
is updated with zero even when it calls api incorrectly are overblown.
diff mbox series

Patch

diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index a8c7e1c5abfa..fa8e3f1e1724 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -1692,6 +1692,13 @@  __htab_map_lookup_and_delete_batch(struct bpf_map *map,
 	struct bucket *b;
 	int ret = 0;
 
+	max_count = attr->batch.count;
+	if (!max_count)
+		return 0;
+
+	if (put_user(0, &uattr->batch.count))
+		return -EFAULT;
+
 	elem_map_flags = attr->batch.elem_flags;
 	if ((elem_map_flags & ~BPF_F_LOCK) ||
 	    ((elem_map_flags & BPF_F_LOCK) && !btf_record_has_field(map->record, BPF_SPIN_LOCK)))
@@ -1701,13 +1708,6 @@  __htab_map_lookup_and_delete_batch(struct bpf_map *map,
 	if (map_flags)
 		return -EINVAL;
 
-	max_count = attr->batch.count;
-	if (!max_count)
-		return 0;
-
-	if (put_user(0, &uattr->batch.count))
-		return -EFAULT;
-
 	batch = 0;
 	if (ubatch && copy_from_user(&batch, ubatch, sizeof(batch)))
 		return -EFAULT;