History

Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Pull bpf fixes from Alexei Starovoitov: - Fix how linked registers track zero extension of subregisters (Daniel Borkmann) - Fix unsound scalar fork for OR instructions (Daniel Wade) - Fix exception exit lock check for subprogs (Ihor Solodrai) - Fix undefined behavior in interpreter for SDIV/SMOD instructions (Jenny Guanni Qu) - Release module's BTF when module is unloaded (Kumar Kartikeya Dwivedi) - Fix constant blinding for PROBE_MEM32 instructions (Sachin Kumar) - Reset register ID for END instructions to prevent incorrect value tracking (Yazhou Tang) * tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: selftests/bpf: Add a test cases for sync_linked_regs regarding zext propagation bpf: Fix sync_linked_regs regarding BPF_ADD_CONST32 zext propagation selftests/bpf: Add tests for maybe_fork_scalars() OR vs AND handling bpf: Fix unsound scalar forking in maybe_fork_scalars() for BPF_OR selftests/bpf: Add tests for sdiv32/smod32 with INT_MIN dividend bpf: Fix undefined behavior in interpreter sdiv/smod for INT_MIN selftests/bpf: Add tests for bpf_throw lock leak from subprogs bpf: Fix exception exit lock checking for subprogs bpf: Release module BTF IDR before module unload selftests/bpf: Fix pkg-config call on static builds bpf: Fix constant blinding for PROBE_MEM32 stores selftests/bpf: Add test for BPF_END register ID reset bpf: Reset register ID for BPF_END value tracking

Linus Torvalds committed 7 months ago

Commit d5273fd2 parents ac57fa9 4a04d139 files · +416 −24Browse files

Unified · Split

9 files
  1. kernel/bpf/btf.c +20 −4
  2. kernel/bpf/core.c +35 −8
  3. kernel/bpf/verifier.c +25 −8
  4. tools/testing/selftests/bpf/Makefile +1 −1
  5. tools/testing/selftests/bpf/progs/exceptions_fail.c +53 −3
  6. tools/testing/selftests/bpf/progs/verifier_bounds.c +94 −0
  7. tools/testing/selftests/bpf/progs/verifier_bswap.c +22 −0
  8. tools/testing/selftests/bpf/progs/verifier_linked_scalars.c +108 −0
  9. tools/testing/selftests/bpf/progs/verifier_sdiv.c +58 −0
kernel/bpf/btf.c+20−4
@@ -1787,7 +1787,16 @@ static void btf_free_id(struct btf *btf) · 1786 unmodified lines
1787 * of the _bh() version.1787 * of the _bh() version.
1788 */1788 */
1789 spin_lock_irqsave(&btf_idr_lock, flags);1789 spin_lock_irqsave(&btf_idr_lock, flags);
1790 idr_remove(&btf_idr, btf->id);1790 if (btf->id) {
1791 idr_remove(&btf_idr, btf->id);
1792 /*
1793 * Clear the id here to make this function idempotent, since it will get
1794 * called a couple of times for module BTFs: on module unload, and then
1795 * the final btf_put(). btf_alloc_id() starts IDs with 1, so we can use
1796 * 0 as sentinel value.
1797 */
1798 WRITE_ONCE(btf->id, 0);
1799 }
1791 spin_unlock_irqrestore(&btf_idr_lock, flags);1800 spin_unlock_irqrestore(&btf_idr_lock, flags);
1792}1801}
1793 1802
@@ -8115,7 +8124,7 @@ static void bpf_btf_show_fdinfo(struct seq_file *m, struct file *filp) · 6321 unmodified lines
8115{8124{
8116 const struct btf *btf = filp->private_data;8125 const struct btf *btf = filp->private_data;
8117 8126
8118 seq_printf(m, "btf_id:\t%u\n", btf->id);8127 seq_printf(m, "btf_id:\t%u\n", READ_ONCE(btf->id));
8119}8128}
8120#endif8129#endif
8121 8130
@@ -8197,7 +8206,7 @@ int btf_get_info_by_fd(const struct btf *btf, · 75 unmodified lines
8197 if (copy_from_user(&info, uinfo, info_copy))8206 if (copy_from_user(&info, uinfo, info_copy))
8198 return -EFAULT;8207 return -EFAULT;
8199 8208
8200 info.id = btf->id;8209 info.id = READ_ONCE(btf->id);
8201 ubtf = u64_to_user_ptr(info.btf);8210 ubtf = u64_to_user_ptr(info.btf);
8202 btf_copy = min_t(u32, btf->data_size, info.btf_size);8211 btf_copy = min_t(u32, btf->data_size, info.btf_size);
8203 if (copy_to_user(ubtf, btf->data, btf_copy))8212 if (copy_to_user(ubtf, btf->data, btf_copy))
@@ -8260,7 +8269,7 @@ int btf_get_fd_by_id(u32 id) · 56 unmodified lines
8260 8269
8261u32 btf_obj_id(const struct btf *btf)8270u32 btf_obj_id(const struct btf *btf)
8262{8271{
8263 return btf->id;8272 return READ_ONCE(btf->id);
8264}8273}
8265 8274
8266bool btf_is_kernel(const struct btf *btf)8275bool btf_is_kernel(const struct btf *btf)
@@ -8382,6 +8391,13 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op, · 115 unmodified lines
8382 if (btf_mod->module != module)8391 if (btf_mod->module != module)
8383 continue;8392 continue;
8384 8393
8394 /*
8395 * For modules, we do the freeing of BTF IDR as soon as
8396 * module goes away to disable BTF discovery, since the
8397 * btf_try_get_module() on such BTFs will fail. This may
8398 * be called again on btf_put(), but it's ok to do so.
8399 */
8400 btf_free_id(btf_mod->btf);
8385 list_del(&btf_mod->list);8401 list_del(&btf_mod->list);
8386 if (btf_mod->sysfs_attr)8402 if (btf_mod->sysfs_attr)
8387 sysfs_remove_bin_file(btf_kobj, btf_mod->sysfs_attr);8403 sysfs_remove_bin_file(btf_kobj, btf_mod->sysfs_attr);
kernel/bpf/core.c+35−8
@@ -1422,6 +1422,27 @@ static int bpf_jit_blind_insn(const struct bpf_insn *from, · 1421 unmodified lines
1422 *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);1422 *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
1423 *to++ = BPF_STX_MEM(from->code, from->dst_reg, BPF_REG_AX, from->off);1423 *to++ = BPF_STX_MEM(from->code, from->dst_reg, BPF_REG_AX, from->off);
1424 break;1424 break;
1425
1426 case BPF_ST | BPF_PROBE_MEM32 | BPF_DW:
1427 case BPF_ST | BPF_PROBE_MEM32 | BPF_W:
1428 case BPF_ST | BPF_PROBE_MEM32 | BPF_H:
1429 case BPF_ST | BPF_PROBE_MEM32 | BPF_B:
1430 *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^
1431 from->imm);
1432 *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
1433 /*
1434 * Cannot use BPF_STX_MEM() macro here as it
1435 * hardcodes BPF_MEM mode, losing PROBE_MEM32
1436 * and breaking arena addressing in the JIT.
1437 */
1438 *to++ = (struct bpf_insn) {
1439 .code = BPF_STX | BPF_PROBE_MEM32 |
1440 BPF_SIZE(from->code),
1441 .dst_reg = from->dst_reg,
1442 .src_reg = BPF_REG_AX,
1443 .off = from->off,
1444 };
1445 break;
1425 }1446 }
1426out:1447out:
1427 return to - to_buff;1448 return to - to_buff;
@@ -1736,6 +1757,12 @@ bool bpf_opcode_in_insntable(u8 code) · 308 unmodified lines
1736}1757}
1737 1758
1738#ifndef CONFIG_BPF_JIT_ALWAYS_ON1759#ifndef CONFIG_BPF_JIT_ALWAYS_ON
1760/* Absolute value of s32 without undefined behavior for S32_MIN */
1761static u32 abs_s32(s32 x)
1762{
1763 return x >= 0 ? (u32)x : -(u32)x;
1764}
1765
1739/**1766/**
1740 * ___bpf_prog_run - run eBPF program on a given context1767 * ___bpf_prog_run - run eBPF program on a given context
1741 * @regs: is the array of MAX_BPF_EXT_REG eBPF pseudo-registers1768 * @regs: is the array of MAX_BPF_EXT_REG eBPF pseudo-registers
@@ -1900,8 +1927,8 @@ select_insn: · 158 unmodified lines
1900 DST = do_div(AX, (u32) SRC);1927 DST = do_div(AX, (u32) SRC);
1901 break;1928 break;
1902 case 1:1929 case 1:
1903 AX = abs((s32)DST);1930 AX = abs_s32((s32)DST);
1904 AX = do_div(AX, abs((s32)SRC));1931 AX = do_div(AX, abs_s32((s32)SRC));
1905 if ((s32)DST < 0)1932 if ((s32)DST < 0)
1906 DST = (u32)-AX;1933 DST = (u32)-AX;
1907 else1934 else
@@ -1928,8 +1955,8 @@ select_insn: · 20 unmodified lines
1928 DST = do_div(AX, (u32) IMM);1955 DST = do_div(AX, (u32) IMM);
1929 break;1956 break;
1930 case 1:1957 case 1:
1931 AX = abs((s32)DST);1958 AX = abs_s32((s32)DST);
1932 AX = do_div(AX, abs((s32)IMM));1959 AX = do_div(AX, abs_s32((s32)IMM));
1933 if ((s32)DST < 0)1960 if ((s32)DST < 0)
1934 DST = (u32)-AX;1961 DST = (u32)-AX;
1935 else1962 else
@@ -1955,8 +1982,8 @@ select_insn: · 19 unmodified lines
1955 DST = (u32) AX;1982 DST = (u32) AX;
1956 break;1983 break;
1957 case 1:1984 case 1:
1958 AX = abs((s32)DST);1985 AX = abs_s32((s32)DST);
1959 do_div(AX, abs((s32)SRC));1986 do_div(AX, abs_s32((s32)SRC));
1960 if (((s32)DST < 0) == ((s32)SRC < 0))1987 if (((s32)DST < 0) == ((s32)SRC < 0))
1961 DST = (u32)AX;1988 DST = (u32)AX;
1962 else1989 else
@@ -1982,8 +2009,8 @@ select_insn: · 19 unmodified lines
1982 DST = (u32) AX;2009 DST = (u32) AX;
1983 break;2010 break;
1984 case 1:2011 case 1:
1985 AX = abs((s32)DST);2012 AX = abs_s32((s32)DST);
1986 do_div(AX, abs((s32)IMM));2013 do_div(AX, abs_s32((s32)IMM));
1987 if (((s32)DST < 0) == ((s32)IMM < 0))2014 if (((s32)DST < 0) == ((s32)IMM < 0))
1988 DST = (u32)AX;2015 DST = (u32)AX;
1989 else2016 else
kernel/bpf/verifier.c+25−8
@@ -15910,6 +15910,13 @@ static void scalar_byte_swap(struct bpf_reg_state *dst_reg, struct bpf_insn *ins · 15909 unmodified lines
15910 /* Apply bswap if alu64 or switch between big-endian and little-endian machines */15910 /* Apply bswap if alu64 or switch between big-endian and little-endian machines */
15911 bool need_bswap = alu64 || (to_le == is_big_endian);15911 bool need_bswap = alu64 || (to_le == is_big_endian);
15912 15912
15913 /*
15914 * If the register is mutated, manually reset its scalar ID to break
15915 * any existing ties and avoid incorrect bounds propagation.
15916 */
15917 if (need_bswap || insn->imm == 16 || insn->imm == 32)
15918 dst_reg->id = 0;
15919
15913 if (need_bswap) {15920 if (need_bswap) {
15914 if (insn->imm == 16)15921 if (insn->imm == 16)
15915 dst_reg->var_off = tnum_bswap16(dst_reg->var_off);15922 dst_reg->var_off = tnum_bswap16(dst_reg->var_off);
@@ -15992,7 +15999,7 @@ static int maybe_fork_scalars(struct bpf_verifier_env *env, struct bpf_insn *ins · 76 unmodified lines
15992 else15999 else
15993 return 0;16000 return 0;
15994 16001
15995 branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);16002 branch = push_stack(env, env->insn_idx, env->insn_idx, false);
15996 if (IS_ERR(branch))16003 if (IS_ERR(branch))
15997 return PTR_ERR(branch);16004 return PTR_ERR(branch);
15998 16005
@@ -17408,6 +17415,12 @@ static void sync_linked_regs(struct bpf_verifier_env *env, struct bpf_verifier_s · 1409 unmodified lines
17408 continue;17415 continue;
17409 if ((reg->id & ~BPF_ADD_CONST) != (known_reg->id & ~BPF_ADD_CONST))17416 if ((reg->id & ~BPF_ADD_CONST) != (known_reg->id & ~BPF_ADD_CONST))
17410 continue;17417 continue;
17418 /*
17419 * Skip mixed 32/64-bit links: the delta relationship doesn't
17420 * hold across different ALU widths.
17421 */
17422 if (((reg->id ^ known_reg->id) & BPF_ADD_CONST) == BPF_ADD_CONST)
17423 continue;
17411 if ((!(reg->id & BPF_ADD_CONST) && !(known_reg->id & BPF_ADD_CONST)) ||17424 if ((!(reg->id & BPF_ADD_CONST) && !(known_reg->id & BPF_ADD_CONST)) ||
17412 reg->off == known_reg->off) {17425 reg->off == known_reg->off) {
17413 s32 saved_subreg_def = reg->subreg_def;17426 s32 saved_subreg_def = reg->subreg_def;
@@ -17435,7 +17448,7 @@ static void sync_linked_regs(struct bpf_verifier_env *env, struct bpf_verifier_s · 21 unmodified lines
17435 scalar32_min_max_add(reg, &fake_reg);17448 scalar32_min_max_add(reg, &fake_reg);
17436 scalar_min_max_add(reg, &fake_reg);17449 scalar_min_max_add(reg, &fake_reg);
17437 reg->var_off = tnum_add(reg->var_off, fake_reg.var_off);17450 reg->var_off = tnum_add(reg->var_off, fake_reg.var_off);
17438 if (known_reg->id & BPF_ADD_CONST32)17451 if ((reg->id | known_reg->id) & BPF_ADD_CONST32)
17439 zext_32_to_64(reg);17452 zext_32_to_64(reg);
17440 reg_bounds_sync(reg);17453 reg_bounds_sync(reg);
17441 }17454 }
@@ -19863,11 +19876,14 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, · 2421 unmodified lines
19863 * Also verify that new value satisfies old value range knowledge.19876 * Also verify that new value satisfies old value range knowledge.
19864 */19877 */
19865 19878
19866 /* ADD_CONST mismatch: different linking semantics */19879 /*
19867 if ((rold->id & BPF_ADD_CONST) && !(rcur->id & BPF_ADD_CONST))19880 * ADD_CONST flags must match exactly: BPF_ADD_CONST32 and
19868 return false;19881 * BPF_ADD_CONST64 have different linking semantics in
19869 19882 * sync_linked_regs() (alu32 zero-extends, alu64 does not),
19870 if (rold->id && !(rold->id & BPF_ADD_CONST) && (rcur->id & BPF_ADD_CONST))19883 * so pruning across different flag types is unsafe.
19884 */
19885 if (rold->id &&
19886 (rold->id & BPF_ADD_CONST) != (rcur->id & BPF_ADD_CONST))
19871 return false;19887 return false;
19872 19888
19873 /* Both have offset linkage: offsets must match */19889 /* Both have offset linkage: offsets must match */
@@ -20904,7 +20920,8 @@ static int process_bpf_exit_full(struct bpf_verifier_env *env, · 1030 unmodified lines
20904 * state when it exits.20920 * state when it exits.
20905 */20921 */
20906 int err = check_resource_leak(env, exception_exit,20922 int err = check_resource_leak(env, exception_exit,
20907 !env->cur_state->curframe,20923 exception_exit || !env->cur_state->curframe,
20924 exception_exit ? "bpf_throw" :
20908 "BPF_EXIT instruction in main prog");20925 "BPF_EXIT instruction in main prog");
20909 if (err)20926 if (err)
20910 return err;20927 return err;
tools/testing/selftests/bpf/Makefile+1−1
@@ -409,7 +409,7 @@ $(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \ · 408 unmodified lines
409 CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" \409 CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" \
410 LIBBPF_INCLUDE=$(HOST_INCLUDE_DIR) \410 LIBBPF_INCLUDE=$(HOST_INCLUDE_DIR) \
411 EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \411 EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
412 HOSTPKG_CONFIG=$(PKG_CONFIG) \412 HOSTPKG_CONFIG='$(PKG_CONFIG)' \
413 OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ)413 OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ)
414 414
415# Get Clang's default includes on this system, as opposed to those seen by415# Get Clang's default includes on this system, as opposed to those seen by
tools/testing/selftests/bpf/progs/exceptions_fail.c+53−3
@@ -8,6 +8,11 @@ · 7 unmodified lines
8#include "bpf_experimental.h"8#include "bpf_experimental.h"
9 9
10extern void bpf_rcu_read_lock(void) __ksym;10extern void bpf_rcu_read_lock(void) __ksym;
11extern void bpf_rcu_read_unlock(void) __ksym;
12extern void bpf_preempt_disable(void) __ksym;
13extern void bpf_preempt_enable(void) __ksym;
14extern void bpf_local_irq_save(unsigned long *) __ksym;
15extern void bpf_local_irq_restore(unsigned long *) __ksym;
11 16
12#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))17#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
13 18
@@ -131,7 +136,7 @@ int reject_subprog_with_lock(void *ctx) · 117 unmodified lines
131}136}
132 137
133SEC("?tc")138SEC("?tc")
134__failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_rcu_read_lock-ed region")139__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
135int reject_with_rcu_read_lock(void *ctx)140int reject_with_rcu_read_lock(void *ctx)
136{141{
137 bpf_rcu_read_lock();142 bpf_rcu_read_lock();
@@ -147,11 +152,13 @@ __noinline static int throwing_subprog(struct __sk_buff *ctx) · 9 unmodified lines
147}152}
148 153
149SEC("?tc")154SEC("?tc")
150__failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_rcu_read_lock-ed region")155__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
151int reject_subprog_with_rcu_read_lock(void *ctx)156int reject_subprog_with_rcu_read_lock(void *ctx)
152{157{
153 bpf_rcu_read_lock();158 bpf_rcu_read_lock();
154 return throwing_subprog(ctx);159 throwing_subprog(ctx);
160 bpf_rcu_read_unlock();
161 return 0;
155}162}
156 163
157static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2)164static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2)
@@ -346,4 +353,47 @@ int reject_exception_throw_cb_diff(struct __sk_buff *ctx) · 188 unmodified lines
346 return 0;353 return 0;
347}354}
348 355
356__noinline static int always_throws(void)
357{
358 bpf_throw(0);
359 return 0;
360}
361
362__noinline static int rcu_lock_then_throw(void)
363{
364 bpf_rcu_read_lock();
365 bpf_throw(0);
366 return 0;
367}
368
369SEC("?tc")
370__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
371int reject_subprog_rcu_lock_throw(void *ctx)
372{
373 rcu_lock_then_throw();
374 return 0;
375}
376
377SEC("?tc")
378__failure __msg("bpf_throw cannot be used inside bpf_preempt_disable-ed region")
379int reject_subprog_throw_preempt_lock(void *ctx)
380{
381 bpf_preempt_disable();
382 always_throws();
383 bpf_preempt_enable();
384 return 0;
385}
386
387SEC("?tc")
388__failure __msg("bpf_throw cannot be used inside bpf_local_irq_save-ed region")
389int reject_subprog_throw_irq_lock(void *ctx)
390{
391 unsigned long flags;
392
393 bpf_local_irq_save(&flags);
394 always_throws();
395 bpf_local_irq_restore(&flags);
396 return 0;
397}
398
349char _license[] SEC("license") = "GPL";399char _license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/verifier_bounds.c+94−0
@@ -2037,4 +2037,98 @@ __naked void signed_unsigned_intersection32_case2(void *ctx) · 2036 unmodified lines
2037 : __clobber_all);2037 : __clobber_all);
2038}2038}
2039 2039
2040SEC("socket")
2041__description("maybe_fork_scalars: OR with constant rejects OOB")
2042__failure __msg("invalid access to map value")
2043__naked void or_scalar_fork_rejects_oob(void)
2044{
2045 asm volatile (" \
2046 r1 = 0; \
2047 *(u64*)(r10 - 8) = r1; \
2048 r2 = r10; \
2049 r2 += -8; \
2050 r1 = %[map_hash_8b] ll; \
2051 call %[bpf_map_lookup_elem]; \
2052 if r0 == 0 goto l0_%=; \
2053 r9 = r0; \
2054 r6 = *(u64*)(r9 + 0); \
2055 r6 s>>= 63; \
2056 r6 |= 8; \
2057 /* r6 is -1 (current) or 8 (pushed) */ \
2058 if r6 s< 0 goto l0_%=; \
2059 /* pushed path: r6 = 8, OOB for value_size=8 */ \
2060 r9 += r6; \
2061 r0 = *(u8*)(r9 + 0); \
2062l0_%=: r0 = 0; \
2063 exit; \
2064" :
2065 : __imm(bpf_map_lookup_elem),
2066 __imm_addr(map_hash_8b)
2067 : __clobber_all);
2068}
2069
2070SEC("socket")
2071__description("maybe_fork_scalars: AND with constant still works")
2072__success __retval(0)
2073__naked void and_scalar_fork_still_works(void)
2074{
2075 asm volatile (" \
2076 r1 = 0; \
2077 *(u64*)(r10 - 8) = r1; \
2078 r2 = r10; \
2079 r2 += -8; \
2080 r1 = %[map_hash_8b] ll; \
2081 call %[bpf_map_lookup_elem]; \
2082 if r0 == 0 goto l0_%=; \
2083 r9 = r0; \
2084 r6 = *(u64*)(r9 + 0); \
2085 r6 s>>= 63; \
2086 r6 &= 4; \
2087 /* \
2088 * r6 is 0 (pushed, 0&4==0) or 4 (current) \
2089 * both within value_size=8 \
2090 */ \
2091 if r6 s< 0 goto l0_%=; \
2092 r9 += r6; \
2093 r0 = *(u8*)(r9 + 0); \
2094l0_%=: r0 = 0; \
2095 exit; \
2096" :
2097 : __imm(bpf_map_lookup_elem),
2098 __imm_addr(map_hash_8b)
2099 : __clobber_all);
2100}
2101
2102SEC("socket")
2103__description("maybe_fork_scalars: OR with constant allows in-bounds")
2104__success __retval(0)
2105__naked void or_scalar_fork_allows_inbounds(void)
2106{
2107 asm volatile (" \
2108 r1 = 0; \
2109 *(u64*)(r10 - 8) = r1; \
2110 r2 = r10; \
2111 r2 += -8; \
2112 r1 = %[map_hash_8b] ll; \
2113 call %[bpf_map_lookup_elem]; \
2114 if r0 == 0 goto l0_%=; \
2115 r9 = r0; \
2116 r6 = *(u64*)(r9 + 0); \
2117 r6 s>>= 63; \
2118 r6 |= 4; \
2119 /* \
2120 * r6 is -1 (current) or 4 (pushed) \
2121 * pushed path: r6 = 4, within value_size=8 \
2122 */ \
2123 if r6 s< 0 goto l0_%=; \
2124 r9 += r6; \
2125 r0 = *(u8*)(r9 + 0); \
2126l0_%=: r0 = 0; \
2127 exit; \
2128" :
2129 : __imm(bpf_map_lookup_elem),
2130 __imm_addr(map_hash_8b)
2131 : __clobber_all);
2132}
2133
2040char _license[] SEC("license") = "GPL";2134char _license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/verifier_bswap.c+22−0
@@ -91,6 +91,28 @@ BSWAP_RANGE_TEST(le32_range, "le32", 0x3f00, 0x3f0000) · 90 unmodified lines
91BSWAP_RANGE_TEST(le64_range, "le64", 0x3f00, 0x3f000000000000)91BSWAP_RANGE_TEST(le64_range, "le64", 0x3f00, 0x3f000000000000)
92#endif92#endif
93 93
94SEC("socket")
95__description("BSWAP, reset reg id")
96__failure __msg("math between fp pointer and register with unbounded min value is not allowed")
97__naked void bswap_reset_reg_id(void)
98{
99 asm volatile (" \
100 call %[bpf_ktime_get_ns]; \
101 r1 = r0; \
102 r0 = be16 r0; \
103 if r0 != 1 goto l0_%=; \
104 r2 = r10; \
105 r2 += -512; \
106 r2 += r1; \
107 *(u8 *)(r2 + 0) = 0; \
108l0_%=: \
109 r0 = 0; \
110 exit; \
111" :
112 : __imm(bpf_ktime_get_ns)
113 : __clobber_all);
114}
115
94#else116#else
95 117
96SEC("socket")118SEC("socket")
tools/testing/selftests/bpf/progs/verifier_linked_scalars.c+108−0
@@ -348,6 +348,114 @@ l0_%=: \ · 347 unmodified lines
348 : __clobber_all);348 : __clobber_all);
349}349}
350 350
351/*
352 * Test that sync_linked_regs() checks reg->id (the linked target register)
353 * for BPF_ADD_CONST32 rather than known_reg->id (the branch register).
354 */
355SEC("socket")
356__success
357__naked void scalars_alu32_zext_linked_reg(void)
358{
359 asm volatile (" \
360 call %[bpf_get_prandom_u32]; \
361 w6 = w0; /* r6 in [0, 0xFFFFFFFF] */ \
362 r7 = r6; /* linked: same id as r6 */ \
363 w7 += 1; /* alu32: r7.id |= BPF_ADD_CONST32 */ \
364 r8 = 0xFFFFffff ll; \
365 if r6 < r8 goto l0_%=; \
366 /* r6 in [0xFFFFFFFF, 0xFFFFFFFF] */ \
367 /* sync_linked_regs: known_reg=r6, reg=r7 */ \
368 /* CPU: w7 = (u32)(0xFFFFFFFF + 1) = 0, zext -> r7 = 0 */ \
369 /* With fix: r7 64-bit = [0, 0] (zext applied) */ \
370 /* Without fix: r7 64-bit = [0x100000000] (no zext) */ \
371 r7 >>= 32; \
372 if r7 == 0 goto l0_%=; \
373 r0 /= 0; /* unreachable with fix */ \
374l0_%=: \
375 r0 = 0; \
376 exit; \
377" :
378 : __imm(bpf_get_prandom_u32)
379 : __clobber_all);
380}
381
382/*
383 * Test that sync_linked_regs() skips propagation when one register used
384 * alu32 (BPF_ADD_CONST32) and the other used alu64 (BPF_ADD_CONST64).
385 * The delta relationship doesn't hold across different ALU widths.
386 */
387SEC("socket")
388__failure __msg("div by zero")
389__naked void scalars_alu32_alu64_cross_type(void)
390{
391 asm volatile (" \
392 call %[bpf_get_prandom_u32]; \
393 w6 = w0; /* r6 in [0, 0xFFFFFFFF] */ \
394 r7 = r6; /* linked: same id as r6 */ \
395 w7 += 1; /* alu32: BPF_ADD_CONST32, delta = 1 */ \
396 r8 = r6; /* linked: same id as r6 */ \
397 r8 += 2; /* alu64: BPF_ADD_CONST64, delta = 2 */ \
398 r9 = 0xFFFFffff ll; \
399 if r7 < r9 goto l0_%=; \
400 /* r7 = 0xFFFFFFFF */ \
401 /* sync: known_reg=r7 (ADD_CONST32), reg=r8 (ADD_CONST64) */ \
402 /* Without fix: r8 = zext(0xFFFFFFFF + 1) = 0 */ \
403 /* With fix: r8 stays [2, 0x100000001] (r8 >= 2) */ \
404 if r8 > 0 goto l1_%=; \
405 goto l0_%=; \
406l1_%=: \
407 r0 /= 0; /* div by zero */ \
408l0_%=: \
409 r0 = 0; \
410 exit; \
411" :
412 : __imm(bpf_get_prandom_u32)
413 : __clobber_all);
414}
415
416/*
417 * Test that regsafe() prevents pruning when two paths reach the same program
418 * point with linked registers carrying different ADD_CONST flags (one
419 * BPF_ADD_CONST32 from alu32, another BPF_ADD_CONST64 from alu64).
420 */
421SEC("socket")
422__failure __msg("div by zero")
423__flag(BPF_F_TEST_STATE_FREQ)
424__naked void scalars_alu32_alu64_regsafe_pruning(void)
425{
426 asm volatile (" \
427 call %[bpf_get_prandom_u32]; \
428 w6 = w0; /* r6 in [0, 0xFFFFFFFF] */ \
429 r7 = r6; /* linked: same id as r6 */ \
430 /* Get another random value for the path branch */ \
431 call %[bpf_get_prandom_u32]; \
432 if r0 > 0 goto l_pathb_%=; \
433 /* Path A: alu32 */ \
434 w7 += 1; /* BPF_ADD_CONST32, delta = 1 */\
435 goto l_merge_%=; \
436l_pathb_%=: \
437 /* Path B: alu64 */ \
438 r7 += 1; /* BPF_ADD_CONST64, delta = 1 */\
439l_merge_%=: \
440 /* Merge point: regsafe() compares path B against cached path A. */ \
441 /* Narrow r6 to trigger sync_linked_regs for r7 */ \
442 r9 = 0xFFFFffff ll; \
443 if r6 < r9 goto l0_%=; \
444 /* r6 = 0xFFFFFFFF */ \
445 /* sync: r7 = 0xFFFFFFFF + 1 = 0x100000000 */ \
446 /* Path A: zext -> r7 = 0 */ \
447 /* Path B: no zext -> r7 = 0x100000000 */ \
448 r7 >>= 32; \
449 if r7 == 0 goto l0_%=; \
450 r0 /= 0; /* div by zero on path B */ \
451l0_%=: \
452 r0 = 0; \
453 exit; \
454" :
455 : __imm(bpf_get_prandom_u32)
456 : __clobber_all);
457}
458
351SEC("socket")459SEC("socket")
352__success460__success
353void alu32_negative_offset(void)461void alu32_negative_offset(void)
tools/testing/selftests/bpf/progs/verifier_sdiv.c+58−0
@@ -1209,6 +1209,64 @@ __naked void smod32_ri_divisor_neg_1(void) · 1208 unmodified lines
1209 : __clobber_all);1209 : __clobber_all);
1210}1210}
1211 1211
1212SEC("socket")
1213__description("SDIV32, INT_MIN divided by 2, imm")
1214__success __success_unpriv __retval(-1073741824)
1215__naked void sdiv32_int_min_div_2_imm(void)
1216{
1217 asm volatile (" \
1218 w0 = %[int_min]; \
1219 w0 s/= 2; \
1220 exit; \
1221" :
1222 : __imm_const(int_min, INT_MIN)
1223 : __clobber_all);
1224}
1225
1226SEC("socket")
1227__description("SDIV32, INT_MIN divided by 2, reg")
1228__success __success_unpriv __retval(-1073741824)
1229__naked void sdiv32_int_min_div_2_reg(void)
1230{
1231 asm volatile (" \
1232 w0 = %[int_min]; \
1233 w1 = 2; \
1234 w0 s/= w1; \
1235 exit; \
1236" :
1237 : __imm_const(int_min, INT_MIN)
1238 : __clobber_all);
1239}
1240
1241SEC("socket")
1242__description("SMOD32, INT_MIN modulo 2, imm")
1243__success __success_unpriv __retval(0)
1244__naked void smod32_int_min_mod_2_imm(void)
1245{
1246 asm volatile (" \
1247 w0 = %[int_min]; \
1248 w0 s%%= 2; \
1249 exit; \
1250" :
1251 : __imm_const(int_min, INT_MIN)
1252 : __clobber_all);
1253}
1254
1255SEC("socket")
1256__description("SMOD32, INT_MIN modulo -2, imm")
1257__success __success_unpriv __retval(0)
1258__naked void smod32_int_min_mod_neg2_imm(void)
1259{
1260 asm volatile (" \
1261 w0 = %[int_min]; \
1262 w0 s%%= -2; \
1263 exit; \
1264" :
1265 : __imm_const(int_min, INT_MIN)
1266 : __clobber_all);
1267}
1268
1269
1212#else1270#else
1213 1271
1214SEC("socket")1272SEC("socket")