Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add test for static subprog call in lock cs

Add selftests for static subprog calls within bpf_spin_lock critical
section, and ensure we still reject global subprog calls. Also test the
case where a subprog call will unlock the caller's held lock, or the
caller will unlock a lock taken by a subprog call, ensuring correct
transfer of lock state across frames on exit.

Acked-by: Yonghong Song <yonghong.song@linux.dev>
Acked-by: David Vernet <void@manifault.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20240204222349.938118-3-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Kumar Kartikeya Dwivedi and committed by
Alexei Starovoitov
e8699c4f a44b1334

+111
+2
tools/testing/selftests/bpf/prog_tests/spin_lock.c
··· 48 48 { "lock_id_mismatch_innermapval_kptr", "bpf_spin_unlock of different lock" }, 49 49 { "lock_id_mismatch_innermapval_global", "bpf_spin_unlock of different lock" }, 50 50 { "lock_id_mismatch_innermapval_mapval", "bpf_spin_unlock of different lock" }, 51 + { "lock_global_subprog_call1", "global function calls are not allowed while holding a lock" }, 52 + { "lock_global_subprog_call2", "global function calls are not allowed while holding a lock" }, 51 53 }; 52 54 53 55 static int match_regex(const char *pattern, const char *string)
+65
tools/testing/selftests/bpf/progs/test_spin_lock.c
··· 101 101 err: 102 102 return err; 103 103 } 104 + 105 + struct bpf_spin_lock lockA __hidden SEC(".data.A"); 106 + 107 + __noinline 108 + static int static_subprog(struct __sk_buff *ctx) 109 + { 110 + volatile int ret = 0; 111 + 112 + if (ctx->protocol) 113 + return ret; 114 + return ret + ctx->len; 115 + } 116 + 117 + __noinline 118 + static int static_subprog_lock(struct __sk_buff *ctx) 119 + { 120 + volatile int ret = 0; 121 + 122 + ret = static_subprog(ctx); 123 + bpf_spin_lock(&lockA); 124 + return ret + ctx->len; 125 + } 126 + 127 + __noinline 128 + static int static_subprog_unlock(struct __sk_buff *ctx) 129 + { 130 + volatile int ret = 0; 131 + 132 + ret = static_subprog(ctx); 133 + bpf_spin_unlock(&lockA); 134 + return ret + ctx->len; 135 + } 136 + 137 + SEC("tc") 138 + int lock_static_subprog_call(struct __sk_buff *ctx) 139 + { 140 + int ret = 0; 141 + 142 + bpf_spin_lock(&lockA); 143 + if (ctx->mark == 42) 144 + ret = static_subprog(ctx); 145 + bpf_spin_unlock(&lockA); 146 + return ret; 147 + } 148 + 149 + SEC("tc") 150 + int lock_static_subprog_lock(struct __sk_buff *ctx) 151 + { 152 + int ret = 0; 153 + 154 + ret = static_subprog_lock(ctx); 155 + bpf_spin_unlock(&lockA); 156 + return ret; 157 + } 158 + 159 + SEC("tc") 160 + int lock_static_subprog_unlock(struct __sk_buff *ctx) 161 + { 162 + int ret = 0; 163 + 164 + bpf_spin_lock(&lockA); 165 + ret = static_subprog_unlock(ctx); 166 + return ret; 167 + } 168 + 104 169 char _license[] SEC("license") = "GPL";
+44
tools/testing/selftests/bpf/progs/test_spin_lock_fail.c
··· 201 201 202 202 #undef CHECK 203 203 204 + __noinline 205 + int global_subprog(struct __sk_buff *ctx) 206 + { 207 + volatile int ret = 0; 208 + 209 + if (ctx->protocol) 210 + ret += ctx->protocol; 211 + return ret + ctx->mark; 212 + } 213 + 214 + __noinline 215 + static int static_subprog_call_global(struct __sk_buff *ctx) 216 + { 217 + volatile int ret = 0; 218 + 219 + if (ctx->protocol) 220 + return ret; 221 + return ret + ctx->len + global_subprog(ctx); 222 + } 223 + 224 + SEC("?tc") 225 + int lock_global_subprog_call1(struct __sk_buff *ctx) 226 + { 227 + int ret = 0; 228 + 229 + bpf_spin_lock(&lockA); 230 + if (ctx->mark == 42) 231 + ret = global_subprog(ctx); 232 + bpf_spin_unlock(&lockA); 233 + return ret; 234 + } 235 + 236 + SEC("?tc") 237 + int lock_global_subprog_call2(struct __sk_buff *ctx) 238 + { 239 + int ret = 0; 240 + 241 + bpf_spin_lock(&lockA); 242 + if (ctx->mark == 42) 243 + ret = static_subprog_call_global(ctx); 244 + bpf_spin_unlock(&lockA); 245 + return ret; 246 + } 247 + 204 248 char _license[] SEC("license") = "GPL";