[PATCH bpf-next v1 13/13] selftests/bpf: Add dynptr helper tests

Kumar Kartikeya Dwivedi
2022-10-18T14:00:29Z

Test that MEM_UNINIT doesn't allow writing dynptr stack slots. Next,
also add a test triggering the memmove case for dynptr_read and
dynptr_write.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
.../testing/selftests/bpf/prog_tests/dynptr.c | 3 ++
.../testing/selftests/bpf/progs/dynptr_fail.c | 35 +++++++++++++++++++
.../selftests/bpf/progs/dynptr_success.c | 20 +++++++++++
3 files changed, 58 insertions(+)

diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c
index 947126d217bd..20910598a0a6 100644
--- a/tools/testing/selftests/bpf/prog_tests/dynptr.c
+++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c
@@ -42,11 +42,14 @@ static struct {
{"release_twice_callback", "arg 1 is an unacquired reference"},
{"dynptr_from_mem_invalid_api",
"Unsupported reg type fp for bpf_dynptr_from_mem data"},
+ {"dynptr_read_into_slot", "potential write to dynptr at off=-16"},
+ {"uninit_write_into_slot", "potential write to dynptr at off=-16"},

/* success cases */
{"test_read_write", NULL},
{"test_data_slice", NULL},
{"test_ringbuf", NULL},
+ {"test_overlap", NULL},
};

static void verify_fail(const char *prog_name, const char *expected_err_msg)
diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
index b0f08ff024fb..43a0ed3736a9 100644
--- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
@@ -622,3 +622,38 @@ int dynptr_from_mem_invalid_api(void *ctx)

return 0;
}
+
+/* Reject writes to dynptr slot from bpf_dynptr_read */
+SEC("?raw_tp")
+int dynptr_read_into_slot(void *ctx)
+{
+ union {
+ struct {
+ char _pad[48];
+ struct bpf_dynptr ptr;
+ };
+ char buf[64];
+ } data;
+
+ bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &data.ptr);
+ /* this should fail */
+ bpf_dynptr_read(data.buf, sizeof(data.buf), &data.ptr, 0, 0);
+
+ return 0;
+}
+
+/* Reject writes to dynptr slot for uninit arg */
+SEC("?raw_tp")
+int uninit_write_into_slot(void *ctx)
+{
+ struct {
+ char buf[64];
+ struct bpf_dynptr ptr;
+ } data;
+
+ bpf_ringbuf_reserve_dynptr(&ringbuf, 80, 0, &data.ptr);
+ /* this should fail */
+ bpf_get_current_comm(data.buf, 80);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c
index a3a6103c8569..401e924b15a0 100644
--- a/tools/testing/selftests/bpf/progs/dynptr_success.c
+++ b/tools/testing/selftests/bpf/progs/dynptr_success.c
@@ -162,3 +162,23 @@ int test_ringbuf(void *ctx)
bpf_ringbuf_discard_dynptr(&ptr, 0);
return 0;
}
+
+SEC("tp/syscalls/sys_enter_nanosleep")
+int test_overlap(void *ctx)
+{
+ struct bpf_dynptr ptr;
+ void *p;
+
+ if (bpf_get_current_pid_tgid() >> 32 != pid)
+ return 0;
+ bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
+ p = bpf_dynptr_data(&ptr, 0, 16);
+ if (!p) {
+ err = 1;
+ goto done;
+ }
+ bpf_dynptr_read(p + 1, 8, &ptr, 0, 0);
+done:
+ bpf_ringbuf_discard_dynptr(&ptr, 0);
+ return 0;
+}
--
2.38.0