Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2022 Facebook */
  3
  4#include <errno.h>
  5#include <string.h>
  6#include <linux/bpf.h>
  7#include <bpf/bpf_helpers.h>
  8#include "bpf_misc.h"
  9
 10char _license[] SEC("license") = "GPL";
 11
 12#define ITER_HELPERS						\
 13	  __imm(bpf_iter_num_new),				\
 14	  __imm(bpf_iter_num_next),				\
 15	  __imm(bpf_iter_num_destroy)
 16
 17SEC("?raw_tp")
 18__success
 19int force_clang_to_emit_btf_for_externs(void *ctx)
 20{
 21	/* we need this as a workaround to enforce compiler emitting BTF
 22	 * information for bpf_iter_num_{new,next,destroy}() kfuncs,
 23	 * as, apparently, it doesn't emit it for symbols only referenced from
 24	 * assembly (or cleanup attribute, for that matter, as well)
 25	 */
 26	bpf_repeat(0);
 27
 28	return 0;
 29}
 30
 31SEC("?raw_tp")
 32__success __log_level(2)
 33__msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")
 34int create_and_destroy(void *ctx)
 35{
 36	struct bpf_iter_num iter;
 37
 38	asm volatile (
 39		/* create iterator */
 40		"r1 = %[iter];"
 41		"r2 = 0;"
 42		"r3 = 1000;"
 43		"call %[bpf_iter_num_new];"
 44		/* destroy iterator */
 45		"r1 = %[iter];"
 46		"call %[bpf_iter_num_destroy];"
 47		:
 48		: __imm_ptr(iter), ITER_HELPERS
 49		: __clobber_common
 50	);
 51
 52	return 0;
 53}
 54
 55SEC("?raw_tp")
 56__failure __msg("Unreleased reference id=1")
 57int create_and_forget_to_destroy_fail(void *ctx)
 58{
 59	struct bpf_iter_num iter;
 60
 61	asm volatile (
 62		/* create iterator */
 63		"r1 = %[iter];"
 64		"r2 = 0;"
 65		"r3 = 1000;"
 66		"call %[bpf_iter_num_new];"
 67		:
 68		: __imm_ptr(iter), ITER_HELPERS
 69		: __clobber_common
 70	);
 71
 72	return 0;
 73}
 74
 75SEC("?raw_tp")
 76__failure __msg("expected an initialized iter_num as arg #0")
 77int destroy_without_creating_fail(void *ctx)
 78{
 79	/* init with zeros to stop verifier complaining about uninit stack */
 80	struct bpf_iter_num iter;
 81
 82	asm volatile (
 83		"r1 = %[iter];"
 84		"call %[bpf_iter_num_destroy];"
 85		:
 86		: __imm_ptr(iter), ITER_HELPERS
 87		: __clobber_common
 88	);
 89
 90	return 0;
 91}
 92
 93SEC("?raw_tp")
 94__failure __msg("expected an initialized iter_num as arg #0")
 95int compromise_iter_w_direct_write_fail(void *ctx)
 96{
 97	struct bpf_iter_num iter;
 98
 99	asm volatile (
100		/* create iterator */
101		"r1 = %[iter];"
102		"r2 = 0;"
103		"r3 = 1000;"
104		"call %[bpf_iter_num_new];"
105
106		/* directly write over first half of iter state */
107		"*(u64 *)(%[iter] + 0) = r0;"
108
109		/* (attempt to) destroy iterator */
110		"r1 = %[iter];"
111		"call %[bpf_iter_num_destroy];"
112		:
113		: __imm_ptr(iter), ITER_HELPERS
114		: __clobber_common
115	);
116
117	return 0;
118}
119
120SEC("?raw_tp")
121__failure __msg("Unreleased reference id=1")
122int compromise_iter_w_direct_write_and_skip_destroy_fail(void *ctx)
123{
124	struct bpf_iter_num iter;
125
126	asm volatile (
127		/* create iterator */
128		"r1 = %[iter];"
129		"r2 = 0;"
130		"r3 = 1000;"
131		"call %[bpf_iter_num_new];"
132
133		/* directly write over first half of iter state */
134		"*(u64 *)(%[iter] + 0) = r0;"
135
136		/* don't destroy iter, leaking ref, which should fail */
137		:
138		: __imm_ptr(iter), ITER_HELPERS
139		: __clobber_common
140	);
141
142	return 0;
143}
144
145SEC("?raw_tp")
146__failure __msg("expected an initialized iter_num as arg #0")
147int compromise_iter_w_helper_write_fail(void *ctx)
148{
149	struct bpf_iter_num iter;
150
151	asm volatile (
152		/* create iterator */
153		"r1 = %[iter];"
154		"r2 = 0;"
155		"r3 = 1000;"
156		"call %[bpf_iter_num_new];"
157
158		/* overwrite 8th byte with bpf_probe_read_kernel() */
159		"r1 = %[iter];"
160		"r1 += 7;"
161		"r2 = 1;"
162		"r3 = 0;" /* NULL */
163		"call %[bpf_probe_read_kernel];"
164
165		/* (attempt to) destroy iterator */
166		"r1 = %[iter];"
167		"call %[bpf_iter_num_destroy];"
168		:
169		: __imm_ptr(iter), ITER_HELPERS, __imm(bpf_probe_read_kernel)
170		: __clobber_common
171	);
172
173	return 0;
174}
175
176static __noinline void subprog_with_iter(void)
177{
178	struct bpf_iter_num iter;
179
180	bpf_iter_num_new(&iter, 0, 1);
181
182	return;
183}
184
185SEC("?raw_tp")
186__failure
187/* ensure there was a call to subprog, which might happen without __noinline */
188__msg("returning from callee:")
189__msg("Unreleased reference id=1")
190int leak_iter_from_subprog_fail(void *ctx)
191{
192	subprog_with_iter();
193
194	return 0;
195}
196
197SEC("?raw_tp")
198__success __log_level(2)
199__msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")
200int valid_stack_reuse(void *ctx)
201{
202	struct bpf_iter_num iter;
203
204	asm volatile (
205		/* create iterator */
206		"r1 = %[iter];"
207		"r2 = 0;"
208		"r3 = 1000;"
209		"call %[bpf_iter_num_new];"
210		/* destroy iterator */
211		"r1 = %[iter];"
212		"call %[bpf_iter_num_destroy];"
213
214		/* now reuse same stack slots */
215
216		/* create iterator */
217		"r1 = %[iter];"
218		"r2 = 0;"
219		"r3 = 1000;"
220		"call %[bpf_iter_num_new];"
221		/* destroy iterator */
222		"r1 = %[iter];"
223		"call %[bpf_iter_num_destroy];"
224		:
225		: __imm_ptr(iter), ITER_HELPERS
226		: __clobber_common
227	);
228
229	return 0;
230}
231
232SEC("?raw_tp")
233__failure __msg("expected uninitialized iter_num as arg #0")
234int double_create_fail(void *ctx)
235{
236	struct bpf_iter_num iter;
237
238	asm volatile (
239		/* create iterator */
240		"r1 = %[iter];"
241		"r2 = 0;"
242		"r3 = 1000;"
243		"call %[bpf_iter_num_new];"
244		/* (attempt to) create iterator again */
245		"r1 = %[iter];"
246		"r2 = 0;"
247		"r3 = 1000;"
248		"call %[bpf_iter_num_new];"
249		/* destroy iterator */
250		"r1 = %[iter];"
251		"call %[bpf_iter_num_destroy];"
252		:
253		: __imm_ptr(iter), ITER_HELPERS
254		: __clobber_common
255	);
256
257	return 0;
258}
259
260SEC("?raw_tp")
261__failure __msg("expected an initialized iter_num as arg #0")
262int double_destroy_fail(void *ctx)
263{
264	struct bpf_iter_num iter;
265
266	asm volatile (
267		/* create iterator */
268		"r1 = %[iter];"
269		"r2 = 0;"
270		"r3 = 1000;"
271		"call %[bpf_iter_num_new];"
272		/* destroy iterator */
273		"r1 = %[iter];"
274		"call %[bpf_iter_num_destroy];"
275		/* (attempt to) destroy iterator again */
276		"r1 = %[iter];"
277		"call %[bpf_iter_num_destroy];"
278		:
279		: __imm_ptr(iter), ITER_HELPERS
280		: __clobber_common
281	);
282
283	return 0;
284}
285
286SEC("?raw_tp")
287__failure __msg("expected an initialized iter_num as arg #0")
288int next_without_new_fail(void *ctx)
289{
290	struct bpf_iter_num iter;
291
292	asm volatile (
293		/* don't create iterator and try to iterate*/
294		"r1 = %[iter];"
295		"call %[bpf_iter_num_next];"
296		/* destroy iterator */
297		"r1 = %[iter];"
298		"call %[bpf_iter_num_destroy];"
299		:
300		: __imm_ptr(iter), ITER_HELPERS
301		: __clobber_common
302	);
303
304	return 0;
305}
306
307SEC("?raw_tp")
308__failure __msg("expected an initialized iter_num as arg #0")
309int next_after_destroy_fail(void *ctx)
310{
311	struct bpf_iter_num iter;
312
313	asm volatile (
314		/* create iterator */
315		"r1 = %[iter];"
316		"r2 = 0;"
317		"r3 = 1000;"
318		"call %[bpf_iter_num_new];"
319		/* destroy iterator */
320		"r1 = %[iter];"
321		"call %[bpf_iter_num_destroy];"
322		/* don't create iterator and try to iterate*/
323		"r1 = %[iter];"
324		"call %[bpf_iter_num_next];"
325		:
326		: __imm_ptr(iter), ITER_HELPERS
327		: __clobber_common
328	);
329
330	return 0;
331}
332
333SEC("?raw_tp")
334__failure __msg("invalid read from stack")
335int __naked read_from_iter_slot_fail(void)
336{
337	asm volatile (
338		/* r6 points to struct bpf_iter_num on the stack */
339		"r6 = r10;"
340		"r6 += -24;"
341
342		/* create iterator */
343		"r1 = r6;"
344		"r2 = 0;"
345		"r3 = 1000;"
346		"call %[bpf_iter_num_new];"
347
348		/* attemp to leak bpf_iter_num state */
349		"r7 = *(u64 *)(r6 + 0);"
350		"r8 = *(u64 *)(r6 + 8);"
351
352		/* destroy iterator */
353		"r1 = r6;"
354		"call %[bpf_iter_num_destroy];"
355
356		/* leak bpf_iter_num state */
357		"r0 = r7;"
358		"if r7 > r8 goto +1;"
359		"r0 = r8;"
360		"exit;"
361		:
362		: ITER_HELPERS
363		: __clobber_common, "r6", "r7", "r8"
364	);
365}
366
367int zero;
368
369SEC("?raw_tp")
370__failure
371__flag(BPF_F_TEST_STATE_FREQ)
372__msg("Unreleased reference")
373int stacksafe_should_not_conflate_stack_spill_and_iter(void *ctx)
374{
375	struct bpf_iter_num iter;
376
377	asm volatile (
378		/* Create a fork in logic, with general setup as follows:
379		 *   - fallthrough (first) path is valid;
380		 *   - branch (second) path is invalid.
381		 * Then depending on what we do in fallthrough vs branch path,
382		 * we try to detect bugs in func_states_equal(), regsafe(),
383		 * refsafe(), stack_safe(), and similar by tricking verifier
384		 * into believing that branch state is a valid subset of
385		 * a fallthrough state. Verifier should reject overall
386		 * validation, unless there is a bug somewhere in verifier
387		 * logic.
388		 */
389		"call %[bpf_get_prandom_u32];"
390		"r6 = r0;"
391		"call %[bpf_get_prandom_u32];"
392		"r7 = r0;"
393
394		"if r6 > r7 goto bad;" /* fork */
395
396		/* spill r6 into stack slot of bpf_iter_num var */
397		"*(u64 *)(%[iter] + 0) = r6;"
398
399		"goto skip_bad;"
400
401	"bad:"
402		/* create iterator in the same stack slot */
403		"r1 = %[iter];"
404		"r2 = 0;"
405		"r3 = 1000;"
406		"call %[bpf_iter_num_new];"
407
408		/* but then forget about it and overwrite it back to r6 spill */
409		"*(u64 *)(%[iter] + 0) = r6;"
410
411	"skip_bad:"
412		"goto +0;" /* force checkpoint */
413
414		/* corrupt stack slots, if they are really dynptr */
415		"*(u64 *)(%[iter] + 0) = r6;"
416		:
417		: __imm_ptr(iter),
418		  __imm_addr(zero),
419		  __imm(bpf_get_prandom_u32),
420		  __imm(bpf_dynptr_from_mem),
421		  ITER_HELPERS
422		: __clobber_common, "r6", "r7"
423	);
424
425	return 0;
426}