summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c189
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_kfunc_uninit.c136
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_kfunc_uninit_multi.c6
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_live_stack.c33
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_raw_stack.c4
-rw-r--r--tools/testing/selftests/bpf/test_kmods/bpf_testmod.c7
-rw-r--r--tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h1
7 files changed, 356 insertions, 20 deletions
diff --git a/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c b/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c
index d1452ef6f2f9..e87eb6f221e4 100644
--- a/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c
+++ b/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c
@@ -822,4 +822,193 @@ __naked void bytes_no_leak_init_memory(void)
: __clobber_all);
}
+SEC("cgroup/sysctl")
+__success
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__success_unpriv
+__naked void sysctl_initialized_stack(void)
+{
+ asm volatile (
+ "*(u64 *)(r10 - 16) = 0;"
+ "*(u64 *)(r10 - 8) = 0;"
+ "r2 = r10;"
+ "r2 += -16;"
+ "r3 = 16;"
+ "r4 = 0;"
+ "call %[bpf_sysctl_get_name];"
+ "r0 = *(u8 *)(r10 - 1);"
+ "r0 &= 1;"
+ "exit;"
+ : : __imm(bpf_sysctl_get_name) : __clobber_all);
+}
+
+SEC("cgroup/sysctl")
+__success
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__success_unpriv
+__naked void sysctl_uninitialized_stack(void)
+{
+ asm volatile (
+ "r2 = r10;"
+ "r2 += -16;"
+ "r3 = 16;"
+ "r4 = 0;"
+ "call %[bpf_sysctl_get_name];"
+ "r0 = 0;"
+ "exit;"
+ : : __imm(bpf_sysctl_get_name) : __clobber_all);
+}
+
+SEC("cgroup/sysctl")
+__success
+__flag(BPF_F_TEST_STATE_FREQ)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__success_unpriv
+__naked void sysctl_partial_initialized_bytes(void)
+{
+ asm volatile (
+ "*(u32 *)(r10 - 16) = 0;"
+ "*(u8 *)(r10 - 1) = 1;"
+ "goto +0;"
+ "r2 = r10;"
+ "r2 += -16;"
+ "r3 = 16;"
+ "r4 = 0;"
+ "call %[bpf_sysctl_get_name];"
+ "r0 = *(u32 *)(r10 - 16);"
+ "r1 = *(u8 *)(r10 - 1);"
+ "r0 += r1;"
+ "r0 &= 1;"
+ "exit;"
+ : : __imm(bpf_sysctl_get_name) : __clobber_all);
+}
+
+SEC("cgroup/sysctl")
+__success
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__failure_unpriv __msg_unpriv("invalid read from stack off -1+0 size 1")
+__naked void sysctl_partial_invalid_bytes(void)
+{
+ asm volatile (
+ "*(u32 *)(r10 - 16) = 0;"
+ "r2 = r10;"
+ "r2 += -16;"
+ "r3 = 16;"
+ "r4 = 0;"
+ "call %[bpf_sysctl_get_name];"
+ "r0 = *(u8 *)(r10 - 1);"
+ "r0 &= 1;"
+ "exit;"
+ : : __imm(bpf_sysctl_get_name) : __clobber_all);
+}
+
+SEC("cgroup/sysctl")
+__success
+__flag(BPF_F_TEST_STATE_FREQ)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__success_unpriv
+__naked void sysctl_partial_variable_size(void)
+{
+ asm volatile (
+ "r3 = *(u32 *)(r1 + 0);"
+ "r3 &= 15;"
+ "r3 += 1;"
+ "*(u8 *)(r10 - 1) = 1;"
+ "goto +0;"
+ "r2 = r10;"
+ "r2 += -16;"
+ "r4 = 0;"
+ "call %[bpf_sysctl_get_name];"
+ "r0 = *(u8 *)(r10 - 1);"
+ "r0 &= 1;"
+ "exit;"
+ : : __imm(bpf_sysctl_get_name) : __clobber_all);
+}
+
+SEC("cgroup/sysctl")
+__success
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__failure_unpriv __msg_unpriv("invalid read from stack off -1+0 size 1")
+__naked void sysctl_partial_variable_invalid(void)
+{
+ asm volatile (
+ "r3 = *(u32 *)(r1 + 0);"
+ "r3 &= 15;"
+ "r3 += 1;"
+ "r2 = r10;"
+ "r2 += -16;"
+ "r4 = 0;"
+ "call %[bpf_sysctl_get_name];"
+ "r0 = *(u8 *)(r10 - 1);"
+ "r0 &= 1;"
+ "exit;"
+ : : __imm(bpf_sysctl_get_name) : __clobber_all);
+}
+
+SEC("cgroup/sysctl")
+__success
+__flag(BPF_F_TEST_STATE_FREQ)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__failure_unpriv __msg_unpriv("invalid read from stack R2")
+__naked void sysctl_partial_spilled_pointer(void)
+{
+ asm volatile (
+ "*(u64 *)(r10 - 8) = r1;"
+ "goto +0;"
+ "r2 = r10;"
+ "r2 += -8;"
+ "r3 = 8;"
+ "r4 = 0;"
+ "call %[bpf_sysctl_get_name];"
+ "r0 = 0;"
+ "exit;"
+ : : __imm(bpf_sysctl_get_name) : __clobber_all);
+}
+
+SEC("cgroup/sysctl")
+__success
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__failure_unpriv __msg_unpriv("invalid read from stack R2")
+int sysctl_partial_dynptr(struct bpf_sysctl *ctx)
+{
+ struct bpf_dynptr ptr;
+ long long key = 0, *data;
+
+ data = bpf_map_lookup_elem(&map_hash_8b, &key);
+ if (!data)
+ return 0;
+ bpf_dynptr_from_mem(data, sizeof(*data), 0, &ptr);
+ bpf_sysctl_get_name(ctx, (char *)&ptr, sizeof(ptr), 0);
+ return 0;
+}
+
+SEC("cgroup/sysctl")
+__success
+__naked void sysctl_partial_variable_offset(void)
+{
+ asm volatile (
+ "r2 = *(u32 *)(r1 + 0);"
+ "r2 &= 8;"
+ "r2 += r10;"
+ "r2 += -24;"
+ "r3 = 16;"
+ "r4 = 0;"
+ "call %[bpf_sysctl_get_name];"
+ "r0 = *(u8 *)(r10 - 16);"
+ "r0 &= 1;"
+ "exit;"
+ : : __imm(bpf_sysctl_get_name) : __clobber_all);
+}
+
+SEC("tc")
+__success __retval(42)
+int snprintf_partial_output_runtime(struct __sk_buff *ctx)
+{
+ char buf[16];
+
+ buf[15] = 42;
+ bpf_snprintf(buf, sizeof(buf), "ok", NULL, 0);
+ return buf[15];
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_kfunc_uninit.c b/tools/testing/selftests/bpf/progs/verifier_kfunc_uninit.c
index f7818303e703..ff2fb36a0260 100644
--- a/tools/testing/selftests/bpf/progs/verifier_kfunc_uninit.c
+++ b/tools/testing/selftests/bpf/progs/verifier_kfunc_uninit.c
@@ -12,6 +12,7 @@ void __kfunc_btf_root(void)
asm volatile ("" :
: "r"(&bpf_kfunc_test_uninit_struct),
"r"(&bpf_kfunc_test_uninit_mem),
+ "r"(&bpf_kfunc_test_uninit_partial),
"r"(&bpf_kfunc_test_uninit_alias));
}
@@ -97,4 +98,139 @@ __naked void uninitialized_input_alias(void)
: : __imm(bpf_kfunc_test_uninit_alias) : __clobber_all);
}
+SEC("tc")
+__success __retval(0)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__prepare_priv
+__success_unpriv
+__naked void uninitialized_struct_output_ignored(void)
+{
+ asm volatile (
+ "r1 = r10;"
+ "r1 += -16;"
+ "call %[bpf_kfunc_test_uninit_struct];"
+ "r0 = 0;"
+ "exit;"
+ : : __imm(bpf_kfunc_test_uninit_struct) : __clobber_all);
+}
+
+SEC("tc")
+__success __retval(0)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__prepare_priv
+__success_unpriv
+__naked void variable_size_uninitialized_output_ignored(void)
+{
+ asm volatile (
+ "r2 = *(u32 *)(r1 + 0);"
+ "r2 &= 7;"
+ "r2 += 1;"
+ "r1 = r10;"
+ "r1 += -8;"
+ "call %[bpf_kfunc_test_uninit_mem];"
+ "r0 = 0;"
+ "exit;"
+ : : __imm(bpf_kfunc_test_uninit_mem) : __clobber_all);
+}
+
+SEC("tc")
+__success __retval(49)
+__flag(BPF_F_TEST_STATE_FREQ)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__prepare_priv
+__success_unpriv
+__naked void partial_output_preserves_initialized_bytes(void)
+{
+ asm volatile (
+ "*(u8 *)(r10 - 8) = 0;"
+ "*(u8 *)(r10 - 1) = 7;"
+ "goto +0;"
+ "r1 = r10;"
+ "r1 += -8;"
+ "r2 = 8;"
+ "call %[bpf_kfunc_test_uninit_partial];"
+ "r0 = *(u8 *)(r10 - 8);"
+ "r1 = *(u8 *)(r10 - 1);"
+ "r0 += r1;"
+ "exit;"
+ : : __imm(bpf_kfunc_test_uninit_partial) : __clobber_all);
+}
+
+SEC("tc")
+__success __retval(42)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__prepare_priv
+__failure_unpriv __msg_unpriv("invalid read from stack off -8+0 size 1")
+__naked void uninitialized_sized_output_read(void)
+{
+ asm volatile (
+ "r1 = r10;"
+ "r1 += -8;"
+ "r2 = 8;"
+ "call %[bpf_kfunc_test_uninit_mem];"
+ "r0 = *(u8 *)(r10 - 8);"
+ "exit;"
+ : : __imm(bpf_kfunc_test_uninit_mem) : __clobber_all);
+}
+
+SEC("tc")
+__success __retval(42)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__prepare_priv
+__failure_unpriv __msg_unpriv("invalid read from stack off -8+0 size 1")
+__naked void variable_size_uninitialized_output_read(void)
+{
+ asm volatile (
+ "r2 = *(u32 *)(r1 + 0);"
+ "r2 &= 7;"
+ "r2 += 1;"
+ "r1 = r10;"
+ "r1 += -8;"
+ "call %[bpf_kfunc_test_uninit_mem];"
+ "r0 = *(u8 *)(r10 - 8);"
+ "exit;"
+ : : __imm(bpf_kfunc_test_uninit_mem) : __clobber_all);
+}
+
+SEC("tc")
+__success __retval(1)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__prepare_priv
+__failure_unpriv __msg_unpriv("invalid read from stack off -16+0 size 4")
+__naked void fixed_struct_uninitialized_output_read(void)
+{
+ asm volatile (
+ "r1 = r10;"
+ "r1 += -16;"
+ "call %[bpf_kfunc_test_uninit_struct];"
+ "r0 = *(u32 *)(r10 - 16);"
+ "exit;"
+ : : __imm(bpf_kfunc_test_uninit_struct) : __clobber_all);
+}
+
+SEC("tc")
+__success __retval(49)
+__flag(BPF_F_TEST_STATE_FREQ)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__prepare_priv
+__success_unpriv
+__naked void partial_output_variable_size(void)
+{
+ asm volatile (
+ "r2 = *(u32 *)(r1 + 0);"
+ "r2 &= 7;"
+ "r2 += 1;"
+ "*(u8 *)(r10 - 8) = 0;"
+ "*(u8 *)(r10 - 1) = 7;"
+ "goto +0;"
+ "r1 = r10;"
+ "r1 += -8;"
+ "call %[bpf_kfunc_test_uninit_partial];"
+ "r0 = *(u8 *)(r10 - 8);"
+ "r1 = *(u8 *)(r10 - 1);"
+ "r0 += r1;"
+ "exit;"
+ : : __imm(bpf_kfunc_test_uninit_partial) : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_kfunc_uninit_multi.c b/tools/testing/selftests/bpf/progs/verifier_kfunc_uninit_multi.c
index 18ced0d0a3b2..ab3bb81a11fd 100644
--- a/tools/testing/selftests/bpf/progs/verifier_kfunc_uninit_multi.c
+++ b/tools/testing/selftests/bpf/progs/verifier_kfunc_uninit_multi.c
@@ -49,7 +49,7 @@ SEC("tc")
__success __retval(42)
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
__prepare_priv
-__success_unpriv
+__failure_unpriv __msg_unpriv("invalid read from stack off -16+0 size 4")
__naked void variable_size_preserves_other_output(void)
{
asm volatile (
@@ -71,7 +71,7 @@ __arch_x86_64 __arch_arm64
__success __retval(42)
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
__prepare_priv
-__success_unpriv
+__failure_unpriv __msg_unpriv("invalid read from stack off -8+0 size 4")
__naked void output_after_by_value_argument(void)
{
asm volatile (
@@ -91,7 +91,7 @@ __arch_x86_64 __arch_arm64 __arch_riscv64
__success __retval(15)
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
__prepare_priv
-__success_unpriv
+__failure_unpriv __msg_unpriv("invalid read from stack off -8+0 size 4")
__naked void output_passed_on_stack(void)
{
asm volatile (
diff --git a/tools/testing/selftests/bpf/progs/verifier_live_stack.c b/tools/testing/selftests/bpf/progs/verifier_live_stack.c
index bc3dfdc1a536..7a1a0670f851 100644
--- a/tools/testing/selftests/bpf/progs/verifier_live_stack.c
+++ b/tools/testing/selftests/bpf/progs/verifier_live_stack.c
@@ -21,8 +21,6 @@ struct {
__type(value, __u64);
} array_map_8b SEC(".maps");
-const char snprintf_u64_fmt[] = "%llu";
-
SEC("socket")
__log_level(2)
__msg("0: (79) r1 = *(u64 *)(r10 -8) ; use: fp0-8")
@@ -1947,15 +1945,15 @@ static __used __naked void fwd_parent_key_to_helper(void)
/*
* Regression for keeping later helper args after a whole-stack fallback
- * on an earlier local arg. The first bpf_snprintf() arg is a local
+ * on an earlier local arg. The bpf_map_update_elem() key is a local
* frame-derived pointer with offset-imprecise tracking (`fp1 ?`), which
- * conservatively marks the whole local stack live. The fourth arg still
+ * conservatively marks the whole local stack live. The value arg still
* forwards &parent_fp-8 and must contribute nonlocal_use[0]=0:3.
*/
SEC("socket")
__log_level(2)
__success
-__msg("call bpf_snprintf{{.*}} ; use: fp1-8..-512 fp0-8")
+__msg("call bpf_map_update_elem{{.*}}; use: fp1-8..-512 fp0-8")
__naked void helper_arg_fallback_keeps_scanning(void)
{
asm volatile (
@@ -1963,32 +1961,33 @@ __naked void helper_arg_fallback_keeps_scanning(void)
"*(u64 *)(r10 - 8) = r1;"
"r1 = r10;"
"r1 += -8;"
- "call helper_snprintf_parent_after_local_fallback;"
+ "call helper_update_parent_after_local_fallback;"
"r0 = 0;"
"exit;"
::: __clobber_all);
}
-static __used __naked void helper_snprintf_parent_after_local_fallback(void)
+static __used __naked void helper_update_parent_after_local_fallback(void)
{
asm volatile (
"r6 = r1;" /* save &parent_fp-8 */
"call %[bpf_get_prandom_u32];"
"r0 &= 8;"
- "r1 = r10;"
- "r1 += -16;"
- "r1 += r0;" /* local fp, offset-imprecise */
- "r2 = 8;"
- "r3 = %[snprintf_u64_fmt] ll;"
- "r4 = r6;" /* later arg: parent fp-8 */
- "r5 = 8;"
- "call %[bpf_snprintf];"
+ "*(u64 *)(r10 - 16) = 0;"
+ "*(u64 *)(r10 - 8) = 0;"
+ "r2 = r10;"
+ "r2 += -16;"
+ "r2 += r0;" /* local fp, offset-imprecise */
+ "r1 = %[array_map_8b] ll;"
+ "r3 = r6;" /* later arg: parent fp-8 */
+ "r4 = 0;"
+ "call %[bpf_map_update_elem];"
"r0 = 0;"
"exit;"
:
: __imm(bpf_get_prandom_u32),
- __imm(bpf_snprintf),
- __imm_addr(snprintf_u64_fmt)
+ __imm(bpf_map_update_elem),
+ __imm_addr(array_map_8b)
: __clobber_all);
}
diff --git a/tools/testing/selftests/bpf/progs/verifier_raw_stack.c b/tools/testing/selftests/bpf/progs/verifier_raw_stack.c
index c689665e07b9..9f0f48ecb421 100644
--- a/tools/testing/selftests/bpf/progs/verifier_raw_stack.c
+++ b/tools/testing/selftests/bpf/progs/verifier_raw_stack.c
@@ -84,6 +84,8 @@ __naked void skb_load_bytes_zero_len(void)
SEC("tc")
__description("raw_stack: skb_load_bytes, no init")
__success __retval(0)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__failure_unpriv __msg_unpriv("invalid read from stack off -8+0 size 8")
__naked void skb_load_bytes_no_init(void)
{
asm volatile (" \
@@ -103,6 +105,8 @@ __naked void skb_load_bytes_no_init(void)
SEC("tc")
__description("raw_stack: skb_load_bytes, init")
__success __retval(0)
+__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
+__success_unpriv
__naked void stack_skb_load_bytes_init(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
index 211886a8ee87..93847ca6293b 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
@@ -1330,6 +1330,12 @@ __bpf_kfunc void bpf_kfunc_test_uninit_mem(void *out__uninit, u32 out__sz)
memset(out__uninit, 0x2a, out__sz);
}
+__bpf_kfunc void bpf_kfunc_test_uninit_partial(void *out__uninit, u32 out__sz)
+{
+ if (out__sz)
+ *(u8 *)out__uninit = 42;
+}
+
__bpf_kfunc int bpf_kfunc_test_uninit_alias(int *out__uninit, const int *in)
{
int value = get_unaligned(in);
@@ -1788,6 +1794,7 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass1)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass2)
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_struct)
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_mem)
+BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_partial)
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_alias)
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_multi)
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_pair)
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
index 524f2cb9bdf4..67c02a421d13 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
@@ -291,6 +291,7 @@ void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym;
void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym;
void bpf_kfunc_test_uninit_struct(struct prog_test_pass1 *out__uninit) __ksym;
void bpf_kfunc_test_uninit_mem(void *out__uninit, __u32 out__sz) __ksym;
+void bpf_kfunc_test_uninit_partial(void *out__uninit, __u32 out__sz) __ksym;
int bpf_kfunc_test_uninit_alias(int *out__uninit, const int *in) __ksym;
void bpf_kfunc_test_uninit_multi(int *a__uninit, void *b__uninit, __u32 b__sz) __ksym;
void bpf_kfunc_test_uninit_pair(struct prog_test_pair_arg p, int *out__uninit) __ksym;