diff mbox series

[bpf-next,v1,2/2] selftests/bpf: add extra test for using dynptr data slice after release

Message ID 20220721024821.251231-2-joannelkoong@gmail.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series [bpf-next,v1,1/2] bpf: Fix ref_obj_id for dynptr data slices in verifier | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Kernel LATEST on ubuntu-latest with llvm-15
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Kernel LATEST on z15 with gcc
bpf/vmtest-bpf-next-VM_Test-1 success Logs for Kernel LATEST on ubuntu-latest with gcc

Commit Message

Joanne Koong July 21, 2022, 2:48 a.m. UTC
Add an additional test, "data_slice_use_after_release2", for ensuring
that data slices are correctly invalidated by the verifier after the
dynptr whose ref obj id they track is released. In particular, this
tests data slice invalidation for dynptrs located at a non-zero offset
from the frame pointer.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 .../testing/selftests/bpf/prog_tests/dynptr.c |  3 +-
 .../testing/selftests/bpf/progs/dynptr_fail.c | 32 ++++++++++++++++++-
 2 files changed, 33 insertions(+), 2 deletions(-)

Comments

Hao Luo July 21, 2022, 5:27 p.m. UTC | #1
Hi Joanne,

On Wed, Jul 20, 2022 at 7:49 PM Joanne Koong <joannelkoong@gmail.com> wrote:
>
> Add an additional test, "data_slice_use_after_release2", for ensuring
> that data slices are correctly invalidated by the verifier after the
> dynptr whose ref obj id they track is released. In particular, this
> tests data slice invalidation for dynptrs located at a non-zero offset
> from the frame pointer.
>
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  .../testing/selftests/bpf/prog_tests/dynptr.c |  3 +-
>  .../testing/selftests/bpf/progs/dynptr_fail.c | 32 ++++++++++++++++++-
>  2 files changed, 33 insertions(+), 2 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> index 3c7aa82b98e2..bcf80b9f7c27 100644
> --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c
> +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> @@ -22,7 +22,8 @@ static struct {
>         {"add_dynptr_to_map2", "invalid indirect read from stack"},
>         {"data_slice_out_of_bounds_ringbuf", "value is outside of the allowed memory range"},
>         {"data_slice_out_of_bounds_map_value", "value is outside of the allowed memory range"},
> -       {"data_slice_use_after_release", "invalid mem access 'scalar'"},
> +       {"data_slice_use_after_release1", "invalid mem access 'scalar'"},
> +       {"data_slice_use_after_release2", "invalid mem access 'scalar'"},
>         {"data_slice_missing_null_check1", "invalid mem access 'mem_or_null'"},
>         {"data_slice_missing_null_check2", "invalid mem access 'mem_or_null'"},
>         {"invalid_helper1", "invalid indirect read from stack"},
> diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> index d811cff73597..d8c4ed3ee146 100644
> --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
> +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> @@ -248,7 +248,7 @@ int data_slice_out_of_bounds_map_value(void *ctx)
>
>  /* A data slice can't be used after it has been released */
>  SEC("?raw_tp/sys_nanosleep")
> -int data_slice_use_after_release(void *ctx)
> +int data_slice_use_after_release1(void *ctx)
>  {
>         struct bpf_dynptr ptr;
>         struct sample *sample;
> @@ -272,6 +272,36 @@ int data_slice_use_after_release(void *ctx)
>         return 0;
>  }
>
> +SEC("?raw_tp/sys_nanosleep")
> +int data_slice_use_after_release2(void *ctx)

Could you put comments explaining the reason for failure, like other test cases?

> +{
> +       struct bpf_dynptr ptr1, ptr2;
> +       struct sample *sample;
> +
> +       bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1);
> +       bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
> +
> +       sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample));
> +       if (!sample)
> +               goto done;
> +
> +       sample->pid = 23;
> +
> +       bpf_ringbuf_submit_dynptr(&ptr2, 0);
> +
> +       /* this should fail */
> +       sample->pid = 23;
> +
> +       bpf_ringbuf_submit_dynptr(&ptr1, 0);
> +
> +       return 0;
> +
> +done:
> +       bpf_ringbuf_discard_dynptr(&ptr2, 0);
> +       bpf_ringbuf_discard_dynptr(&ptr1, 0);
> +       return 0;
> +}
> +

Joanne, I haven't been following the effort of dynptr, so I am still
learning dynptr. Is there any use of `ptr1` in this test case?

>  /* A data slice must be first checked for NULL */
>  SEC("?raw_tp/sys_nanosleep")
>  int data_slice_missing_null_check1(void *ctx)
> --
> 2.30.2
>
Joanne Koong July 22, 2022, 4:40 p.m. UTC | #2
On Thu, Jul 21, 2022 at 10:28 AM Hao Luo <haoluo@google.com> wrote:
>
> Hi Joanne,
>
> On Wed, Jul 20, 2022 at 7:49 PM Joanne Koong <joannelkoong@gmail.com> wrote:
> >
> > Add an additional test, "data_slice_use_after_release2", for ensuring
> > that data slices are correctly invalidated by the verifier after the
> > dynptr whose ref obj id they track is released. In particular, this
> > tests data slice invalidation for dynptrs located at a non-zero offset
> > from the frame pointer.
> >
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  .../testing/selftests/bpf/prog_tests/dynptr.c |  3 +-
> >  .../testing/selftests/bpf/progs/dynptr_fail.c | 32 ++++++++++++++++++-
> >  2 files changed, 33 insertions(+), 2 deletions(-)
> >
> > diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > index 3c7aa82b98e2..bcf80b9f7c27 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > @@ -22,7 +22,8 @@ static struct {
> >         {"add_dynptr_to_map2", "invalid indirect read from stack"},
> >         {"data_slice_out_of_bounds_ringbuf", "value is outside of the allowed memory range"},
> >         {"data_slice_out_of_bounds_map_value", "value is outside of the allowed memory range"},
> > -       {"data_slice_use_after_release", "invalid mem access 'scalar'"},
> > +       {"data_slice_use_after_release1", "invalid mem access 'scalar'"},
> > +       {"data_slice_use_after_release2", "invalid mem access 'scalar'"},
> >         {"data_slice_missing_null_check1", "invalid mem access 'mem_or_null'"},
> >         {"data_slice_missing_null_check2", "invalid mem access 'mem_or_null'"},
> >         {"invalid_helper1", "invalid indirect read from stack"},
> > diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > index d811cff73597..d8c4ed3ee146 100644
> > --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > @@ -248,7 +248,7 @@ int data_slice_out_of_bounds_map_value(void *ctx)
> >
> >  /* A data slice can't be used after it has been released */
> >  SEC("?raw_tp/sys_nanosleep")
> > -int data_slice_use_after_release(void *ctx)
> > +int data_slice_use_after_release1(void *ctx)
> >  {
> >         struct bpf_dynptr ptr;
> >         struct sample *sample;
> > @@ -272,6 +272,36 @@ int data_slice_use_after_release(void *ctx)
> >         return 0;
> >  }
> >
> > +SEC("?raw_tp/sys_nanosleep")
> > +int data_slice_use_after_release2(void *ctx)
>
> Could you put comments explaining the reason for failure, like other test cases?
>
Hi Hao. The explanation for the data_slice_use_after_release test
cases is above the "data_slice_use_after_release1" case, but I can
also copy/paste that comment to above "data_slice_use_after_release2"
as well to make it easier to spot. I'll do that for v2.
> > +{
> > +       struct bpf_dynptr ptr1, ptr2;
> > +       struct sample *sample;
> > +
> > +       bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1);
> > +       bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
> > +
> > +       sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample));
> > +       if (!sample)
> > +               goto done;
> > +
> > +       sample->pid = 23;
> > +
> > +       bpf_ringbuf_submit_dynptr(&ptr2, 0);
> > +
> > +       /* this should fail */
> > +       sample->pid = 23;
> > +
> > +       bpf_ringbuf_submit_dynptr(&ptr1, 0);
> > +
> > +       return 0;
> > +
> > +done:
> > +       bpf_ringbuf_discard_dynptr(&ptr2, 0);
> > +       bpf_ringbuf_discard_dynptr(&ptr1, 0);
> > +       return 0;
> > +}
> > +
>
> Joanne, I haven't been following the effort of dynptr, so I am still
> learning dynptr. Is there any use of `ptr1` in this test case?

The use of ptr1 is so that ptr2 will be at a non-zero offset from the
frame pointer. This bug previously was unspotted because we were only
testing invalidated data slices for ptrs that were at a zero offset.

I will include a comment about this in the test to make it more clear :)

>
> >  /* A data slice must be first checked for NULL */
> >  SEC("?raw_tp/sys_nanosleep")
> >  int data_slice_missing_null_check1(void *ctx)
> > --
> > 2.30.2
> >
Hao Luo July 22, 2022, 7:25 p.m. UTC | #3
On Fri, Jul 22, 2022 at 9:40 AM Joanne Koong <joannelkoong@gmail.com> wrote:
>
> On Thu, Jul 21, 2022 at 10:28 AM Hao Luo <haoluo@google.com> wrote:
> >
> > Hi Joanne,
> >
> > On Wed, Jul 20, 2022 at 7:49 PM Joanne Koong <joannelkoong@gmail.com> wrote:
> > >
> > > Add an additional test, "data_slice_use_after_release2", for ensuring
> > > that data slices are correctly invalidated by the verifier after the
> > > dynptr whose ref obj id they track is released. In particular, this
> > > tests data slice invalidation for dynptrs located at a non-zero offset
> > > from the frame pointer.
> > >
> > > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > > ---
> > >  .../testing/selftests/bpf/prog_tests/dynptr.c |  3 +-
> > >  .../testing/selftests/bpf/progs/dynptr_fail.c | 32 ++++++++++++++++++-
> > >  2 files changed, 33 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > > index 3c7aa82b98e2..bcf80b9f7c27 100644
> > > --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > > +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > > @@ -22,7 +22,8 @@ static struct {
> > >         {"add_dynptr_to_map2", "invalid indirect read from stack"},
> > >         {"data_slice_out_of_bounds_ringbuf", "value is outside of the allowed memory range"},
> > >         {"data_slice_out_of_bounds_map_value", "value is outside of the allowed memory range"},
> > > -       {"data_slice_use_after_release", "invalid mem access 'scalar'"},
> > > +       {"data_slice_use_after_release1", "invalid mem access 'scalar'"},
> > > +       {"data_slice_use_after_release2", "invalid mem access 'scalar'"},
> > >         {"data_slice_missing_null_check1", "invalid mem access 'mem_or_null'"},
> > >         {"data_slice_missing_null_check2", "invalid mem access 'mem_or_null'"},
> > >         {"invalid_helper1", "invalid indirect read from stack"},
> > > diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > > index d811cff73597..d8c4ed3ee146 100644
> > > --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > > +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > > @@ -248,7 +248,7 @@ int data_slice_out_of_bounds_map_value(void *ctx)
> > >
> > >  /* A data slice can't be used after it has been released */
> > >  SEC("?raw_tp/sys_nanosleep")
> > > -int data_slice_use_after_release(void *ctx)
> > > +int data_slice_use_after_release1(void *ctx)
> > >  {
> > >         struct bpf_dynptr ptr;
> > >         struct sample *sample;
> > > @@ -272,6 +272,36 @@ int data_slice_use_after_release(void *ctx)
> > >         return 0;
> > >  }
> > >
> > > +SEC("?raw_tp/sys_nanosleep")
> > > +int data_slice_use_after_release2(void *ctx)
> >
> > Could you put comments explaining the reason for failure, like other test cases?
> >
> Hi Hao. The explanation for the data_slice_use_after_release test
> cases is above the "data_slice_use_after_release1" case, but I can
> also copy/paste that comment to above "data_slice_use_after_release2"
> as well to make it easier to spot. I'll do that for v2.

Thanks Joanne, appreciate the comment about the cause of failure! I
noticed that in other test cases like

ringbuf_missing_release1()
ringbuf_missing_release2()

There is a general description before the release1, and more details
inside each function. Maybe following that convention is better? Sorry
for having many requests from me. :)

> > > +{
> > > +       struct bpf_dynptr ptr1, ptr2;
> > > +       struct sample *sample;
> > > +
> > > +       bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1);
> > > +       bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
> > > +
> > > +       sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample));
> > > +       if (!sample)
> > > +               goto done;
> > > +
> > > +       sample->pid = 23;
> > > +
> > > +       bpf_ringbuf_submit_dynptr(&ptr2, 0);
> > > +
> > > +       /* this should fail */
> > > +       sample->pid = 23;
> > > +
> > > +       bpf_ringbuf_submit_dynptr(&ptr1, 0);
> > > +
> > > +       return 0;
> > > +
> > > +done:
> > > +       bpf_ringbuf_discard_dynptr(&ptr2, 0);
> > > +       bpf_ringbuf_discard_dynptr(&ptr1, 0);
> > > +       return 0;
> > > +}
> > > +
> >
> > Joanne, I haven't been following the effort of dynptr, so I am still
> > learning dynptr. Is there any use of `ptr1` in this test case?
>
> The use of ptr1 is so that ptr2 will be at a non-zero offset from the
> frame pointer. This bug previously was unspotted because we were only
> testing invalidated data slices for ptrs that were at a zero offset.
>
> I will include a comment about this in the test to make it more clear :)
>

Sounds good. It would be great if we can fix that bug and spare the
use of ptr1 here.

Thanks!

> >
> > >  /* A data slice must be first checked for NULL */
> > >  SEC("?raw_tp/sys_nanosleep")
> > >  int data_slice_missing_null_check1(void *ctx)
> > > --
> > > 2.30.2
> > >
Hao Luo July 22, 2022, 7:33 p.m. UTC | #4
On Fri, Jul 22, 2022 at 12:25 PM Hao Luo <haoluo@google.com> wrote:
>
> On Fri, Jul 22, 2022 at 9:40 AM Joanne Koong <joannelkoong@gmail.com> wrote:
> >
> > On Thu, Jul 21, 2022 at 10:28 AM Hao Luo <haoluo@google.com> wrote:
> > >
> > > Hi Joanne,
> > >
> > > On Wed, Jul 20, 2022 at 7:49 PM Joanne Koong <joannelkoong@gmail.com> wrote:
> > > >
> > > > Add an additional test, "data_slice_use_after_release2", for ensuring
> > > > that data slices are correctly invalidated by the verifier after the
> > > > dynptr whose ref obj id they track is released. In particular, this
> > > > tests data slice invalidation for dynptrs located at a non-zero offset
> > > > from the frame pointer.
> > > >
> > > > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > > > ---
> > > >  .../testing/selftests/bpf/prog_tests/dynptr.c |  3 +-
> > > >  .../testing/selftests/bpf/progs/dynptr_fail.c | 32 ++++++++++++++++++-
> > > >  2 files changed, 33 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > > > index 3c7aa82b98e2..bcf80b9f7c27 100644
> > > > --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > > > +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> > > > @@ -22,7 +22,8 @@ static struct {
> > > >         {"add_dynptr_to_map2", "invalid indirect read from stack"},
> > > >         {"data_slice_out_of_bounds_ringbuf", "value is outside of the allowed memory range"},
> > > >         {"data_slice_out_of_bounds_map_value", "value is outside of the allowed memory range"},
> > > > -       {"data_slice_use_after_release", "invalid mem access 'scalar'"},
> > > > +       {"data_slice_use_after_release1", "invalid mem access 'scalar'"},
> > > > +       {"data_slice_use_after_release2", "invalid mem access 'scalar'"},
> > > >         {"data_slice_missing_null_check1", "invalid mem access 'mem_or_null'"},
> > > >         {"data_slice_missing_null_check2", "invalid mem access 'mem_or_null'"},
> > > >         {"invalid_helper1", "invalid indirect read from stack"},
> > > > diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > > > index d811cff73597..d8c4ed3ee146 100644
> > > > --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > > > +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > > > @@ -248,7 +248,7 @@ int data_slice_out_of_bounds_map_value(void *ctx)
> > > >
> > > >  /* A data slice can't be used after it has been released */
> > > >  SEC("?raw_tp/sys_nanosleep")
> > > > -int data_slice_use_after_release(void *ctx)
> > > > +int data_slice_use_after_release1(void *ctx)
> > > >  {
> > > >         struct bpf_dynptr ptr;
> > > >         struct sample *sample;
> > > > @@ -272,6 +272,36 @@ int data_slice_use_after_release(void *ctx)
> > > >         return 0;
> > > >  }
> > > >
> > > > +SEC("?raw_tp/sys_nanosleep")
> > > > +int data_slice_use_after_release2(void *ctx)
> > >
> > > Could you put comments explaining the reason for failure, like other test cases?
> > >
> > Hi Hao. The explanation for the data_slice_use_after_release test
> > cases is above the "data_slice_use_after_release1" case, but I can
> > also copy/paste that comment to above "data_slice_use_after_release2"
> > as well to make it easier to spot. I'll do that for v2.
>
> Thanks Joanne, appreciate the comment about the cause of failure! I
> noticed that in other test cases like
>
> ringbuf_missing_release1()
> ringbuf_missing_release2()
>
> There is a general description before the release1, and more details
> inside each function. Maybe following that convention is better? Sorry
> for having many requests from me. :)
>
> > > > +{
> > > > +       struct bpf_dynptr ptr1, ptr2;
> > > > +       struct sample *sample;
> > > > +
> > > > +       bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1);
> > > > +       bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
> > > > +
> > > > +       sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample));
> > > > +       if (!sample)
> > > > +               goto done;
> > > > +
> > > > +       sample->pid = 23;
> > > > +
> > > > +       bpf_ringbuf_submit_dynptr(&ptr2, 0);
> > > > +
> > > > +       /* this should fail */
> > > > +       sample->pid = 23;
> > > > +
> > > > +       bpf_ringbuf_submit_dynptr(&ptr1, 0);
> > > > +
> > > > +       return 0;
> > > > +
> > > > +done:
> > > > +       bpf_ringbuf_discard_dynptr(&ptr2, 0);
> > > > +       bpf_ringbuf_discard_dynptr(&ptr1, 0);
> > > > +       return 0;
> > > > +}
> > > > +
> > >
> > > Joanne, I haven't been following the effort of dynptr, so I am still
> > > learning dynptr. Is there any use of `ptr1` in this test case?
> >
> > The use of ptr1 is so that ptr2 will be at a non-zero offset from the
> > frame pointer. This bug previously was unspotted because we were only
> > testing invalidated data slices for ptrs that were at a zero offset.
> >
> > I will include a comment about this in the test to make it more clear :)
> >
>
> Sounds good. It would be great if we can fix that bug and spare the
> use of ptr1 here.

Sorry, I don't mean we should do it in this patchset.

>
> Thanks!
>
> > >
> > > >  /* A data slice must be first checked for NULL */
> > > >  SEC("?raw_tp/sys_nanosleep")
> > > >  int data_slice_missing_null_check1(void *ctx)
> > > > --
> > > > 2.30.2
> > > >
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c
index 3c7aa82b98e2..bcf80b9f7c27 100644
--- a/tools/testing/selftests/bpf/prog_tests/dynptr.c
+++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c
@@ -22,7 +22,8 @@  static struct {
 	{"add_dynptr_to_map2", "invalid indirect read from stack"},
 	{"data_slice_out_of_bounds_ringbuf", "value is outside of the allowed memory range"},
 	{"data_slice_out_of_bounds_map_value", "value is outside of the allowed memory range"},
-	{"data_slice_use_after_release", "invalid mem access 'scalar'"},
+	{"data_slice_use_after_release1", "invalid mem access 'scalar'"},
+	{"data_slice_use_after_release2", "invalid mem access 'scalar'"},
 	{"data_slice_missing_null_check1", "invalid mem access 'mem_or_null'"},
 	{"data_slice_missing_null_check2", "invalid mem access 'mem_or_null'"},
 	{"invalid_helper1", "invalid indirect read from stack"},
diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
index d811cff73597..d8c4ed3ee146 100644
--- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
@@ -248,7 +248,7 @@  int data_slice_out_of_bounds_map_value(void *ctx)
 
 /* A data slice can't be used after it has been released */
 SEC("?raw_tp/sys_nanosleep")
-int data_slice_use_after_release(void *ctx)
+int data_slice_use_after_release1(void *ctx)
 {
 	struct bpf_dynptr ptr;
 	struct sample *sample;
@@ -272,6 +272,36 @@  int data_slice_use_after_release(void *ctx)
 	return 0;
 }
 
+SEC("?raw_tp/sys_nanosleep")
+int data_slice_use_after_release2(void *ctx)
+{
+	struct bpf_dynptr ptr1, ptr2;
+	struct sample *sample;
+
+	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1);
+	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
+
+	sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample));
+	if (!sample)
+		goto done;
+
+	sample->pid = 23;
+
+	bpf_ringbuf_submit_dynptr(&ptr2, 0);
+
+	/* this should fail */
+	sample->pid = 23;
+
+	bpf_ringbuf_submit_dynptr(&ptr1, 0);
+
+	return 0;
+
+done:
+	bpf_ringbuf_discard_dynptr(&ptr2, 0);
+	bpf_ringbuf_discard_dynptr(&ptr1, 0);
+	return 0;
+}
+
 /* A data slice must be first checked for NULL */
 SEC("?raw_tp/sys_nanosleep")
 int data_slice_missing_null_check1(void *ctx)