History

Merge tag 'for-netdev' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Daniel Borkmann says: ==================== pull-request: bpf 2024-06-24 We've added 12 non-merge commits during the last 10 day(s) which contain a total of 10 files changed, 412 insertions(+), 16 deletions(-). The main changes are: 1) Fix a BPF verifier issue validating may_goto with a negative offset, from Alexei Starovoitov. 2) Fix a BPF verifier validation bug with may_goto combined with jump to the first instruction, also from Alexei Starovoitov. 3) Fix a bug with overrunning reservations in BPF ring buffer, from Daniel Borkmann. 4) Fix a bug in BPF verifier due to missing proper var_off setting related to movsx instruction, from Yonghong Song. 5) Silence unnecessary syzkaller-triggered warning in __xdp_reg_mem_model(), from Daniil Dulov. * tag 'for-netdev' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: xdp: Remove WARN() from __xdp_reg_mem_model() selftests/bpf: Add tests for may_goto with negative offset. bpf: Fix may_goto with negative offset. selftests/bpf: Add more ring buffer test coverage bpf: Fix overrunning reservations in ringbuf selftests/bpf: Tests with may_goto and jumps to the 1st insn bpf: Fix the corner case with may_goto and jump to the 1st insn. bpf: Update BPF LSM maintainer list bpf: Fix remap of arena. selftests/bpf: Add a few tests to cover bpf: Add missed var_off setting in coerce_subreg_to_size_sx() bpf: Add missed var_off setting in set_sext32_default_val() ====================

Jakub Kicinski committed 2 years ago

Commit 482000c2 parents 058722e 7e9f79410 files · +412 −16Browse files

Unified · Split

10 files
  1. MAINTAINERS +2 −1
  2. kernel/bpf/arena.c +14 −2
  3. kernel/bpf/ringbuf.c +25 −6
  4. kernel/bpf/verifier.c +58 −3
  5. net/core/xdp.c +1 −3
  6. tools/testing/selftests/bpf/Makefile +1 −1
  7. tools/testing/selftests/bpf/prog_tests/ringbuf.c +56 −0
  8. tools/testing/selftests/bpf/progs/test_ringbuf_write.c +46 −0
  9. tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c +146 −0
  10. tools/testing/selftests/bpf/progs/verifier_movsx.c +63 −0
MAINTAINERS+2−1
@@ -4083,12 +4083,13 @@ F: kernel/bpf/ringbuf.c · 4082 unmodified lines
4083 4083
4084BPF [SECURITY & LSM] (Security Audit and Enforcement using BPF)4084BPF [SECURITY & LSM] (Security Audit and Enforcement using BPF)
4085M: KP Singh <kpsingh@kernel.org>4085M: KP Singh <kpsingh@kernel.org>
4086R: Matt Bobrowski <mattbobrowski@google.com>4086M: Matt Bobrowski <mattbobrowski@google.com>
4087L: bpf@vger.kernel.org4087L: bpf@vger.kernel.org
4088S: Maintained4088S: Maintained
4089F: Documentation/bpf/prog_lsm.rst4089F: Documentation/bpf/prog_lsm.rst
4090F: include/linux/bpf_lsm.h4090F: include/linux/bpf_lsm.h
4091F: kernel/bpf/bpf_lsm.c4091F: kernel/bpf/bpf_lsm.c
4092F: kernel/trace/bpf_trace.c
4092F: security/bpf/4093F: security/bpf/
4093 4094
4094BPF [SELFTESTS] (Test Runners & Infrastructure)4095BPF [SELFTESTS] (Test Runners & Infrastructure)
kernel/bpf/arena.c+14−2
@@ -212,6 +212,7 @@ static u64 arena_map_mem_usage(const struct bpf_map *map) · 211 unmodified lines
212struct vma_list {212struct vma_list {
213 struct vm_area_struct *vma;213 struct vm_area_struct *vma;
214 struct list_head head;214 struct list_head head;
215 atomic_t mmap_count;
215};216};
216 217
217static int remember_vma(struct bpf_arena *arena, struct vm_area_struct *vma)218static int remember_vma(struct bpf_arena *arena, struct vm_area_struct *vma)
@@ -221,20 +222,30 @@ static int remember_vma(struct bpf_arena *arena, struct vm_area_struct *vma) · 3 unmodified lines
221 vml = kmalloc(sizeof(*vml), GFP_KERNEL);222 vml = kmalloc(sizeof(*vml), GFP_KERNEL);
222 if (!vml)223 if (!vml)
223 return -ENOMEM;224 return -ENOMEM;
225 atomic_set(&vml->mmap_count, 1);
224 vma->vm_private_data = vml;226 vma->vm_private_data = vml;
225 vml->vma = vma;227 vml->vma = vma;
226 list_add(&vml->head, &arena->vma_list);228 list_add(&vml->head, &arena->vma_list);
227 return 0;229 return 0;
228}230}
229 231
232static void arena_vm_open(struct vm_area_struct *vma)
233{
234 struct vma_list *vml = vma->vm_private_data;
235
236 atomic_inc(&vml->mmap_count);
237}
238
230static void arena_vm_close(struct vm_area_struct *vma)239static void arena_vm_close(struct vm_area_struct *vma)
231{240{
232 struct bpf_map *map = vma->vm_file->private_data;241 struct bpf_map *map = vma->vm_file->private_data;
233 struct bpf_arena *arena = container_of(map, struct bpf_arena, map);242 struct bpf_arena *arena = container_of(map, struct bpf_arena, map);
234 struct vma_list *vml;243 struct vma_list *vml = vma->vm_private_data;
235 244
245 if (!atomic_dec_and_test(&vml->mmap_count))
246 return;
236 guard(mutex)(&arena->lock);247 guard(mutex)(&arena->lock);
237 vml = vma->vm_private_data;248 /* update link list under lock */
238 list_del(&vml->head);249 list_del(&vml->head);
239 vma->vm_private_data = NULL;250 vma->vm_private_data = NULL;
240 kfree(vml);251 kfree(vml);
@@ -287,6 +298,7 @@ out: · 46 unmodified lines
287}298}
288 299
289static const struct vm_operations_struct arena_vm_ops = {300static const struct vm_operations_struct arena_vm_ops = {
301 .open = arena_vm_open,
290 .close = arena_vm_close,302 .close = arena_vm_close,
291 .fault = arena_vm_fault,303 .fault = arena_vm_fault,
292};304};
kernel/bpf/ringbuf.c+25−6
@@ -51,7 +51,8 @@ struct bpf_ringbuf { · 50 unmodified lines
51 * This prevents a user-space application from modifying the51 * This prevents a user-space application from modifying the
52 * position and ruining in-kernel tracking. The permissions of the52 * position and ruining in-kernel tracking. The permissions of the
53 * pages depend on who is producing samples: user-space or the53 * pages depend on who is producing samples: user-space or the
54 * kernel.54 * kernel. Note that the pending counter is placed in the same
55 * page as the producer, so that it shares the same cache line.
55 *56 *
56 * Kernel-producer57 * Kernel-producer
57 * ---------------58 * ---------------
@@ -70,6 +71,7 @@ struct bpf_ringbuf { · 12 unmodified lines
70 */71 */
71 unsigned long consumer_pos __aligned(PAGE_SIZE);72 unsigned long consumer_pos __aligned(PAGE_SIZE);
72 unsigned long producer_pos __aligned(PAGE_SIZE);73 unsigned long producer_pos __aligned(PAGE_SIZE);
74 unsigned long pending_pos;
73 char data[] __aligned(PAGE_SIZE);75 char data[] __aligned(PAGE_SIZE);
74};76};
75 77
@@ -179,6 +181,7 @@ static struct bpf_ringbuf *bpf_ringbuf_alloc(size_t data_sz, int numa_node) · 103 unmodified lines
179 rb->mask = data_sz - 1;181 rb->mask = data_sz - 1;
180 rb->consumer_pos = 0;182 rb->consumer_pos = 0;
181 rb->producer_pos = 0;183 rb->producer_pos = 0;
184 rb->pending_pos = 0;
182 185
183 return rb;186 return rb;
184}187}
@@ -404,9 +407,9 @@ bpf_ringbuf_restore_from_rec(struct bpf_ringbuf_hdr *hdr) · 219 unmodified lines
404 407
405static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size)408static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size)
406{409{
407 unsigned long cons_pos, prod_pos, new_prod_pos, flags;410 unsigned long cons_pos, prod_pos, new_prod_pos, pend_pos, flags;
408 u32 len, pg_off;
409 struct bpf_ringbuf_hdr *hdr;411 struct bpf_ringbuf_hdr *hdr;
412 u32 len, pg_off, tmp_size, hdr_len;
410 413
411 if (unlikely(size > RINGBUF_MAX_RECORD_SZ))414 if (unlikely(size > RINGBUF_MAX_RECORD_SZ))
412 return NULL;415 return NULL;
@@ -424,13 +427,29 @@ static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size) · 11 unmodified lines
424 spin_lock_irqsave(&rb->spinlock, flags);427 spin_lock_irqsave(&rb->spinlock, flags);
425 }428 }
426 429
430 pend_pos = rb->pending_pos;
427 prod_pos = rb->producer_pos;431 prod_pos = rb->producer_pos;
428 new_prod_pos = prod_pos + len;432 new_prod_pos = prod_pos + len;
429 433
430 /* check for out of ringbuf space by ensuring producer position434 while (pend_pos < prod_pos) {
431 * doesn't advance more than (ringbuf_size - 1) ahead435 hdr = (void *)rb->data + (pend_pos & rb->mask);
436 hdr_len = READ_ONCE(hdr->len);
437 if (hdr_len & BPF_RINGBUF_BUSY_BIT)
438 break;
439 tmp_size = hdr_len & ~BPF_RINGBUF_DISCARD_BIT;
440 tmp_size = round_up(tmp_size + BPF_RINGBUF_HDR_SZ, 8);
441 pend_pos += tmp_size;
442 }
443 rb->pending_pos = pend_pos;
444
445 /* check for out of ringbuf space:
446 * - by ensuring producer position doesn't advance more than
447 * (ringbuf_size - 1) ahead
448 * - by ensuring oldest not yet committed record until newest
449 * record does not span more than (ringbuf_size - 1)
432 */450 */
433 if (new_prod_pos - cons_pos > rb->mask) {451 if (new_prod_pos - cons_pos > rb->mask ||
452 new_prod_pos - pend_pos > rb->mask) {
434 spin_unlock_irqrestore(&rb->spinlock, flags);453 spin_unlock_irqrestore(&rb->spinlock, flags);
435 return NULL;454 return NULL;
436 }455 }
kernel/bpf/verifier.c+58−3
@@ -6236,6 +6236,7 @@ static void set_sext32_default_val(struct bpf_reg_state *reg, int size) · 6235 unmodified lines
6236 }6236 }
6237 reg->u32_min_value = 0;6237 reg->u32_min_value = 0;
6238 reg->u32_max_value = U32_MAX;6238 reg->u32_max_value = U32_MAX;
6239 reg->var_off = tnum_subreg(tnum_unknown);
6239}6240}
6240 6241
6241static void coerce_subreg_to_size_sx(struct bpf_reg_state *reg, int size)6242static void coerce_subreg_to_size_sx(struct bpf_reg_state *reg, int size)
@@ -6280,6 +6281,7 @@ static void coerce_subreg_to_size_sx(struct bpf_reg_state *reg, int size) · 38 unmodified lines
6280 reg->s32_max_value = s32_max;6281 reg->s32_max_value = s32_max;
6281 reg->u32_min_value = (u32)s32_min;6282 reg->u32_min_value = (u32)s32_min;
6282 reg->u32_max_value = (u32)s32_max;6283 reg->u32_max_value = (u32)s32_max;
6284 reg->var_off = tnum_subreg(tnum_range(s32_min, s32_max));
6283 return;6285 return;
6284 }6286 }
6285 6287
@@ -12719,6 +12721,16 @@ static bool signed_add32_overflows(s32 a, s32 b) · 6433 unmodified lines
12719 return res < a;12721 return res < a;
12720}12722}
12721 12723
12724static bool signed_add16_overflows(s16 a, s16 b)
12725{
12726 /* Do the add in u16, where overflow is well-defined */
12727 s16 res = (s16)((u16)a + (u16)b);
12728
12729 if (b < 0)
12730 return res > a;
12731 return res < a;
12732}
12733
12722static bool signed_sub_overflows(s64 a, s64 b)12734static bool signed_sub_overflows(s64 a, s64 b)
12723{12735{
12724 /* Do the sub in u64, where overflow is well-defined */12736 /* Do the sub in u64, where overflow is well-defined */
@@ -17448,11 +17460,11 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) · 4723 unmodified lines
17448 goto skip_inf_loop_check;17460 goto skip_inf_loop_check;
17449 }17461 }
17450 if (is_may_goto_insn_at(env, insn_idx)) {17462 if (is_may_goto_insn_at(env, insn_idx)) {
17451 if (states_equal(env, &sl->state, cur, RANGE_WITHIN)) {17463 if (sl->state.may_goto_depth != cur->may_goto_depth &&
17464 states_equal(env, &sl->state, cur, RANGE_WITHIN)) {
17452 update_loop_entry(cur, &sl->state);17465 update_loop_entry(cur, &sl->state);
17453 goto hit;17466 goto hit;
17454 }17467 }
17455 goto skip_inf_loop_check;
17456 }17468 }
17457 if (calls_callback(env, insn_idx)) {17469 if (calls_callback(env, insn_idx)) {
17458 if (states_equal(env, &sl->state, cur, RANGE_WITHIN))17470 if (states_equal(env, &sl->state, cur, RANGE_WITHIN))
@@ -18730,6 +18742,39 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of · 1271 unmodified lines
18730 return new_prog;18742 return new_prog;
18731}18743}
18732 18744
18745/*
18746 * For all jmp insns in a given 'prog' that point to 'tgt_idx' insn adjust the
18747 * jump offset by 'delta'.
18748 */
18749static int adjust_jmp_off(struct bpf_prog *prog, u32 tgt_idx, u32 delta)
18750{
18751 struct bpf_insn *insn = prog->insnsi;
18752 u32 insn_cnt = prog->len, i;
18753
18754 for (i = 0; i < insn_cnt; i++, insn++) {
18755 u8 code = insn->code;
18756
18757 if ((BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32) ||
18758 BPF_OP(code) == BPF_CALL || BPF_OP(code) == BPF_EXIT)
18759 continue;
18760
18761 if (insn->code == (BPF_JMP32 | BPF_JA)) {
18762 if (i + 1 + insn->imm != tgt_idx)
18763 continue;
18764 if (signed_add32_overflows(insn->imm, delta))
18765 return -ERANGE;
18766 insn->imm += delta;
18767 } else {
18768 if (i + 1 + insn->off != tgt_idx)
18769 continue;
18770 if (signed_add16_overflows(insn->imm, delta))
18771 return -ERANGE;
18772 insn->off += delta;
18773 }
18774 }
18775 return 0;
18776}
18777
18733static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env,18778static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env,
18734 u32 off, u32 cnt)18779 u32 off, u32 cnt)
18735{18780{
@@ -20004,7 +20049,10 @@ static int do_misc_fixups(struct bpf_verifier_env *env) · 1268 unmodified lines
20004 20049
20005 stack_depth_extra = 8;20050 stack_depth_extra = 8;
20006 insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_AX, BPF_REG_10, stack_off);20051 insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_AX, BPF_REG_10, stack_off);
20007 insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off + 2);20052 if (insn->off >= 0)
20053 insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off + 2);
20054 else
20055 insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off - 1);
20008 insn_buf[2] = BPF_ALU64_IMM(BPF_SUB, BPF_REG_AX, 1);20056 insn_buf[2] = BPF_ALU64_IMM(BPF_SUB, BPF_REG_AX, 1);
20009 insn_buf[3] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_AX, stack_off);20057 insn_buf[3] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_AX, stack_off);
20010 cnt = 4;20058 cnt = 4;
@@ -20546,6 +20594,13 @@ next_insn: · 535 unmodified lines
20546 if (!new_prog)20594 if (!new_prog)
20547 return -ENOMEM;20595 return -ENOMEM;
20548 env->prog = prog = new_prog;20596 env->prog = prog = new_prog;
20597 /*
20598 * If may_goto is a first insn of a prog there could be a jmp
20599 * insn that points to it, hence adjust all such jmps to point
20600 * to insn after BPF_ST that inits may_goto count.
20601 * Adjustment will succeed because bpf_patch_insn_data() didn't fail.
20602 */
20603 WARN_ON(adjust_jmp_off(env->prog, subprog_start, 1));
20549 }20604 }
20550 20605
20551 /* Since poke tab is now finalized, publish aux to tracker. */20606 /* Since poke tab is now finalized, publish aux to tracker. */
net/core/xdp.c+1−3
@@ -295,10 +295,8 @@ static struct xdp_mem_allocator *__xdp_reg_mem_model(struct xdp_mem_info *mem, · 294 unmodified lines
295 mutex_lock(&mem_id_lock);295 mutex_lock(&mem_id_lock);
296 ret = __mem_id_init_hash_table();296 ret = __mem_id_init_hash_table();
297 mutex_unlock(&mem_id_lock);297 mutex_unlock(&mem_id_lock);
298 if (ret < 0) {298 if (ret < 0)
299 WARN_ON(1);
300 return ERR_PTR(ret);299 return ERR_PTR(ret);
301 }
302 }300 }
303 301
304 xdp_alloc = kzalloc(sizeof(*xdp_alloc), gfp);302 xdp_alloc = kzalloc(sizeof(*xdp_alloc), gfp);
tools/testing/selftests/bpf/Makefile+1−1
@@ -457,7 +457,7 @@ LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h \ · 456 unmodified lines
457LSKELS := fentry_test.c fexit_test.c fexit_sleep.c atomics.c \457LSKELS := fentry_test.c fexit_test.c fexit_sleep.c atomics.c \
458 trace_printk.c trace_vprintk.c map_ptr_kern.c \458 trace_printk.c trace_vprintk.c map_ptr_kern.c \
459 core_kern.c core_kern_overflow.c test_ringbuf.c \459 core_kern.c core_kern_overflow.c test_ringbuf.c \
460 test_ringbuf_n.c test_ringbuf_map_key.c460 test_ringbuf_n.c test_ringbuf_map_key.c test_ringbuf_write.c
461 461
462# Generate both light skeleton and libbpf skeleton for these462# Generate both light skeleton and libbpf skeleton for these
463LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test.c \463LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test.c \
tools/testing/selftests/bpf/prog_tests/ringbuf.c+56−0
@@ -12,9 +12,11 @@ · 11 unmodified lines
12#include <sys/sysinfo.h>12#include <sys/sysinfo.h>
13#include <linux/perf_event.h>13#include <linux/perf_event.h>
14#include <linux/ring_buffer.h>14#include <linux/ring_buffer.h>
15
15#include "test_ringbuf.lskel.h"16#include "test_ringbuf.lskel.h"
16#include "test_ringbuf_n.lskel.h"17#include "test_ringbuf_n.lskel.h"
17#include "test_ringbuf_map_key.lskel.h"18#include "test_ringbuf_map_key.lskel.h"
19#include "test_ringbuf_write.lskel.h"
18 20
19#define EDONE 777721#define EDONE 7777
20 22
@@ -84,6 +86,58 @@ static void *poll_thread(void *input) · 63 unmodified lines
84 return (void *)(long)ring_buffer__poll(ringbuf, timeout);86 return (void *)(long)ring_buffer__poll(ringbuf, timeout);
85}87}
86 88
89static void ringbuf_write_subtest(void)
90{
91 struct test_ringbuf_write_lskel *skel;
92 int page_size = getpagesize();
93 size_t *mmap_ptr;
94 int err, rb_fd;
95
96 skel = test_ringbuf_write_lskel__open();
97 if (!ASSERT_OK_PTR(skel, "skel_open"))
98 return;
99
100 skel->maps.ringbuf.max_entries = 0x4000;
101
102 err = test_ringbuf_write_lskel__load(skel);
103 if (!ASSERT_OK(err, "skel_load"))
104 goto cleanup;
105
106 rb_fd = skel->maps.ringbuf.map_fd;
107
108 mmap_ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, rb_fd, 0);
109 if (!ASSERT_OK_PTR(mmap_ptr, "rw_cons_pos"))
110 goto cleanup;
111 *mmap_ptr = 0x3000;
112 ASSERT_OK(munmap(mmap_ptr, page_size), "unmap_rw");
113
114 skel->bss->pid = getpid();
115
116 ringbuf = ring_buffer__new(rb_fd, process_sample, NULL, NULL);
117 if (!ASSERT_OK_PTR(ringbuf, "ringbuf_new"))
118 goto cleanup;
119
120 err = test_ringbuf_write_lskel__attach(skel);
121 if (!ASSERT_OK(err, "skel_attach"))
122 goto cleanup_ringbuf;
123
124 skel->bss->discarded = 0;
125 skel->bss->passed = 0;
126
127 /* trigger exactly two samples */
128 syscall(__NR_getpgid);
129 syscall(__NR_getpgid);
130
131 ASSERT_EQ(skel->bss->discarded, 2, "discarded");
132 ASSERT_EQ(skel->bss->passed, 0, "passed");
133
134 test_ringbuf_write_lskel__detach(skel);
135cleanup_ringbuf:
136 ring_buffer__free(ringbuf);
137cleanup:
138 test_ringbuf_write_lskel__destroy(skel);
139}
140
87static void ringbuf_subtest(void)141static void ringbuf_subtest(void)
88{142{
89 const size_t rec_sz = BPF_RINGBUF_HDR_SZ + sizeof(struct sample);143 const size_t rec_sz = BPF_RINGBUF_HDR_SZ + sizeof(struct sample);
@@ -451,4 +505,6 @@ void test_ringbuf(void) · 361 unmodified lines
451 ringbuf_n_subtest();505 ringbuf_n_subtest();
452 if (test__start_subtest("ringbuf_map_key"))506 if (test__start_subtest("ringbuf_map_key"))
453 ringbuf_map_key_subtest();507 ringbuf_map_key_subtest();
508 if (test__start_subtest("ringbuf_write"))
509 ringbuf_write_subtest();
454}510}
tools/testing/selftests/bpf/progs/test_ringbuf_write.c+46−0
@@ -0,0 +1,46 @@
1// SPDX-License-Identifier: GPL-2.0
2
3#include <linux/bpf.h>
4#include <bpf/bpf_helpers.h>
5#include "bpf_misc.h"
6
7char _license[] SEC("license") = "GPL";
8
9struct {
10 __uint(type, BPF_MAP_TYPE_RINGBUF);
11} ringbuf SEC(".maps");
12
13/* inputs */
14int pid = 0;
15
16/* outputs */
17long passed = 0;
18long discarded = 0;
19
20SEC("fentry/" SYS_PREFIX "sys_getpgid")
21int test_ringbuf_write(void *ctx)
22{
23 int *foo, cur_pid = bpf_get_current_pid_tgid() >> 32;
24 void *sample1, *sample2;
25
26 if (cur_pid != pid)
27 return 0;
28
29 sample1 = bpf_ringbuf_reserve(&ringbuf, 0x3000, 0);
30 if (!sample1)
31 return 0;
32 /* first one can pass */
33 sample2 = bpf_ringbuf_reserve(&ringbuf, 0x3000, 0);
34 if (!sample2) {
35 bpf_ringbuf_discard(sample1, 0);
36 __sync_fetch_and_add(&discarded, 1);
37 return 0;
38 }
39 /* second one must not */
40 __sync_fetch_and_add(&passed, 1);
41 foo = sample2 + 4084;
42 *foo = 256;
43 bpf_ringbuf_discard(sample1, 0);
44 bpf_ringbuf_discard(sample2, 0);
45 return 0;
46}
tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c+146−0
@@ -274,6 +274,58 @@ static __naked void iter_limit_bug_cb(void) · 273 unmodified lines
274 );274 );
275}275}
276 276
277int tmp_var;
278SEC("socket")
279__failure __msg("infinite loop detected at insn 2")
280__naked void jgt_imm64_and_may_goto(void)
281{
282 asm volatile (" \
283 r0 = %[tmp_var] ll; \
284l0_%=: .byte 0xe5; /* may_goto */ \
285 .byte 0; /* regs */ \
286 .short -3; /* off -3 */ \
287 .long 0; /* imm */ \
288 if r0 > 10 goto l0_%=; \
289 r0 = 0; \
290 exit; \
291" :: __imm_addr(tmp_var)
292 : __clobber_all);
293}
294
295SEC("socket")
296__failure __msg("infinite loop detected at insn 1")
297__naked void may_goto_self(void)
298{
299 asm volatile (" \
300 r0 = *(u32 *)(r10 - 4); \
301l0_%=: .byte 0xe5; /* may_goto */ \
302 .byte 0; /* regs */ \
303 .short -1; /* off -1 */ \
304 .long 0; /* imm */ \
305 if r0 > 10 goto l0_%=; \
306 r0 = 0; \
307 exit; \
308" ::: __clobber_all);
309}
310
311SEC("socket")
312__success __retval(0)
313__naked void may_goto_neg_off(void)
314{
315 asm volatile (" \
316 r0 = *(u32 *)(r10 - 4); \
317 goto l0_%=; \
318 goto l1_%=; \
319l0_%=: .byte 0xe5; /* may_goto */ \
320 .byte 0; /* regs */ \
321 .short -2; /* off -2 */ \
322 .long 0; /* imm */ \
323 if r0 > 10 goto l0_%=; \
324l1_%=: r0 = 0; \
325 exit; \
326" ::: __clobber_all);
327}
328
277SEC("tc")329SEC("tc")
278__failure330__failure
279__flag(BPF_F_TEST_STATE_FREQ)331__flag(BPF_F_TEST_STATE_FREQ)
@@ -307,6 +359,100 @@ int iter_limit_bug(struct __sk_buff *skb) · 27 unmodified lines
307 return 0;359 return 0;
308}360}
309 361
362SEC("socket")
363__success __retval(0)
364__naked void ja_and_may_goto(void)
365{
366 asm volatile (" \
367l0_%=: .byte 0xe5; /* may_goto */ \
368 .byte 0; /* regs */ \
369 .short 1; /* off 1 */ \
370 .long 0; /* imm */ \
371 goto l0_%=; \
372 r0 = 0; \
373 exit; \
374" ::: __clobber_common);
375}
376
377SEC("socket")
378__success __retval(0)
379__naked void ja_and_may_goto2(void)
380{
381 asm volatile (" \
382l0_%=: r0 = 0; \
383 .byte 0xe5; /* may_goto */ \
384 .byte 0; /* regs */ \
385 .short 1; /* off 1 */ \
386 .long 0; /* imm */ \
387 goto l0_%=; \
388 r0 = 0; \
389 exit; \
390" ::: __clobber_common);
391}
392
393SEC("socket")
394__success __retval(0)
395__naked void jlt_and_may_goto(void)
396{
397 asm volatile (" \
398l0_%=: call %[bpf_jiffies64]; \
399 .byte 0xe5; /* may_goto */ \
400 .byte 0; /* regs */ \
401 .short 1; /* off 1 */ \
402 .long 0; /* imm */ \
403 if r0 < 10 goto l0_%=; \
404 r0 = 0; \
405 exit; \
406" :: __imm(bpf_jiffies64)
407 : __clobber_all);
408}
409
410#if (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \
411 (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64) || \
412 defined(__TARGET_ARCH_arm) || defined(__TARGET_ARCH_s390) || \
413 defined(__TARGET_ARCH_loongarch)) && \
414 __clang_major__ >= 18
415SEC("socket")
416__success __retval(0)
417__naked void gotol_and_may_goto(void)
418{
419 asm volatile (" \
420l0_%=: r0 = 0; \
421 .byte 0xe5; /* may_goto */ \
422 .byte 0; /* regs */ \
423 .short 1; /* off 1 */ \
424 .long 0; /* imm */ \
425 gotol l0_%=; \
426 r0 = 0; \
427 exit; \
428" ::: __clobber_common);
429}
430#endif
431
432SEC("socket")
433__success __retval(0)
434__naked void ja_and_may_goto_subprog(void)
435{
436 asm volatile (" \
437 call subprog_with_may_goto; \
438 exit; \
439" ::: __clobber_all);
440}
441
442static __naked __noinline __used
443void subprog_with_may_goto(void)
444{
445 asm volatile (" \
446l0_%=: .byte 0xe5; /* may_goto */ \
447 .byte 0; /* regs */ \
448 .short 1; /* off 1 */ \
449 .long 0; /* imm */ \
450 goto l0_%=; \
451 r0 = 0; \
452 exit; \
453" ::: __clobber_all);
454}
455
310#define ARR_SZ 1000000456#define ARR_SZ 1000000
311int zero;457int zero;
312char arr[ARR_SZ];458char arr[ARR_SZ];
tools/testing/selftests/bpf/progs/verifier_movsx.c+63−0
@@ -224,6 +224,69 @@ l0_%=: \ · 223 unmodified lines
224 : __clobber_all);224 : __clobber_all);
225}225}
226 226
227SEC("socket")
228__description("MOV32SX, S8, var_off u32_max")
229__failure __msg("infinite loop detected")
230__failure_unpriv __msg_unpriv("back-edge from insn 2 to 0")
231__naked void mov64sx_s32_varoff_1(void)
232{
233 asm volatile (" \
234l0_%=: \
235 r3 = *(u8 *)(r10 -387); \
236 w7 = (s8)w3; \
237 if w7 >= 0x2533823b goto l0_%=; \
238 w0 = 0; \
239 exit; \
240" :
241 :
242 : __clobber_all);
243}
244
245SEC("socket")
246__description("MOV32SX, S8, var_off not u32_max, positive after s8 extension")
247__success __retval(0)
248__failure_unpriv __msg_unpriv("frame pointer is read only")
249__naked void mov64sx_s32_varoff_2(void)
250{
251 asm volatile (" \
252 call %[bpf_get_prandom_u32]; \
253 r3 = r0; \
254 r3 &= 0xf; \
255 w7 = (s8)w3; \
256 if w7 s>= 16 goto l0_%=; \
257 w0 = 0; \
258 exit; \
259l0_%=: \
260 r10 = 1; \
261 exit; \
262" :
263 : __imm(bpf_get_prandom_u32)
264 : __clobber_all);
265}
266
267SEC("socket")
268__description("MOV32SX, S8, var_off not u32_max, negative after s8 extension")
269__success __retval(0)
270__failure_unpriv __msg_unpriv("frame pointer is read only")
271__naked void mov64sx_s32_varoff_3(void)
272{
273 asm volatile (" \
274 call %[bpf_get_prandom_u32]; \
275 r3 = r0; \
276 r3 &= 0xf; \
277 r3 |= 0x80; \
278 w7 = (s8)w3; \
279 if w7 s>= -5 goto l0_%=; \
280 w0 = 0; \
281 exit; \
282l0_%=: \
283 r10 = 1; \
284 exit; \
285" :
286 : __imm(bpf_get_prandom_u32)
287 : __clobber_all);
288}
289
227#else290#else
228 291
229SEC("socket")292SEC("socket")