Re: Backporting callback handling fixes to stable 6.1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jun 21, 2024 at 01:27:44AM GMT, Eduard Zingerman wrote:
> On Thu, 2024-06-20 at 13:18 +0800, Shung-Hsi Yu wrote:
> > I'm seeking suggestions for backporting callback handling fixes to the
> > stable/linux-6.1.y (and similar branches), akin to what has been done
> > for 6.6[1].
> 
> I remember that porting to 6.6 was somewhat painful,
> 6.1 would be much worse, probably...

Indeed, my head hurts. While I still don't have detailed understanding
of every change, managed to get an initial working prototype that
correctly rejects the reproducer.

> > Testing with the reproducer from Andrew Werner[2] it seems 6.1 has the
> > same problem where the bpf_probe_read_user() call is only verified with
> > the R1_w=fp-8 state, but not the R1_w=0xDEAD state because the latter
> > was incorrectly pruned. So I believe the callback fixes are need.
> 
> Yes, the main problem with callbacks was that they were verified as if
> called only once. This affects all functions accepting callbacks.

Ah, so my statement that the states are "incorrectly pruned" is not
right, I guess such statement only applies to BPF open-coded iterator
perhaps. Feel free to correct me on this.

> > The main difference from 6.6 is that 6.1 does not have BPF open-coded
> > iterator, but AFAICT it does not mean "exact states comparison for
> > iterator convergence checks" patch-set[3] can be dropped. This is
> > because exact-state comparison from commit 2793a8b015f7 ("bpf: exact
> > states comparison for iterator convergence checks") and loop-identifying
> > algorithm in commit 2a0992829ea3 ("bpf: correct loop detection for
> > iterators convergence") are critical for the fix; but it should be fine
> > to ignore all changes to process_iter_*().
> 
> That is correct, that is the main mechanics of the fix.
> 
> > The "verify callbacks as if they are called unknown number of
> > times" patch-set[4] name already suggest that it is needed, so no doubts
> > there (again, dropping iterator-related changes).
> 
> Right.
> 
> I looked at the patches migrated for 6.6 vs current state of 6.1,
> some thoughts below.

Thanks for looking into this. I picked up quite a handful of commits
along the way (totaling to 39 patches at the moment), many of which you
have mentioned below. The current work can be found on

	https://github.com/shunghsiyu/linux/commits/stable/linux-6.1.y-callback-fixes-w-subprog-precision-v0

Here's a overview of the commits I've picked up. (Note: mostly ignored
selftests for now, will work on backporting them later)


stricter register ID checking in regsafe()[1]
---------------------------------------------
Pulled for regsafe()-related changes (mainly idmap), note entirely sure
if it necessary to fix the issue, but makes backporting the next
patch-set much easier.

1.  7c884339bbff "bpf: regsafe() must not skip check_ids()"
2.  cb578c1c9cf6 "selftests/bpf: test cases for regsafe() bug skipping check_id()"
3.  5dd9cdbc9dec "bpf: states_equal() must build idmap for all function frames"
4.  7d0579433087 "selftests/bpf: verify states_equal() maintains idmap across all frames"
5.  4ea2bb158bec "bpf: use check_ids() for active_lock comparison"
	- commit d0d78c1df9b1 ("bpf: Allow locking bpf_spin_lock global
	  variables") does not exist yet we have active_spin_lock instead of
	  active_lock.id in bpf_verifier_state, and no active_lock.ptr
6.  2026f2062df8 "selftests/bpf: Add pruning test case for bpf_spin_lock"
7.  efd6286ff74a "selftests/bpf: test case for relaxed prunning of active_lock.id"


BPF verifier state equivalence checks improvements[2]
-----------------------------------------------------
Pulled for state equivalent checks change (mainly regsafe()-related, as
well as adding regs_exact()) needed by commit 2793a8b015f7 ("bpf: exact
states comparison for iterator convergence checks").

1.  e8f55fcf7779 "bpf: teach refsafe() to take into account ID remapping"
2.  a73bf9f2d969 "bpf: reorganize struct bpf_reg_state fields"
3.  7f4ce97cd5ed "bpf: generalize MAYBE_NULL vs non-MAYBE_NULL rule"
4.  910f69996674 "bpf: reject non-exact register type matches in regsafe()"
5.  4a95c85c9948 "bpf: perform byte-by-byte comparison only when necessary in regsafe()"
6.  4633a0068258 "bpf: fix regs_exact() logic in regsafe() to remap IDs correctly"


4b5ce570dbef "bpf: ensure state checkpointing at iter_next() call sites"[3]
---------------------------------------------------------------------------
standalone patch for getting mark_force_checkpoint() helper that force
creation of check points, it is used later in backport of commit
2793a8b015f7 ("bpf: exact states comparison for iterator convergence
checks") and ab5cfac139ab ("bpf: verify callbacks as if they are called
unknown number of times").

However the hunk that uses mark_force_checkpoint() in this commit is
dropped because commit 06accc8779c1d ("bpf: add support for open-coded
iterator loops") is not in stable 6.1.


Improve verifier u32 scalar equality checking" series[5]
--------------------------------------------------------
Unrelated patch-set that was pulled for context to make backporting of
commit 1ffc85d9298e "bpf: Verify scalar ids mapping in regsafe() using
check_ids()" easier within check_alu_op().

1. 3be49f79555e bpf: Improve verifier u32 scalar equality checking
2. 49859de997c3 selftests/bpf: Add a selftest for checking subreg equality
   - dropped for now


Add precision propagation for subprogs and callbacks[4]
-------------------------------------------------------
Pulled for 407958a0e980 "bpf: encapsulate precision backtracking
bookkeeping" and fde2a3882bd0 "bpf: support precision propagation in the
presence of subprogs". While the former is just refactoring (which is
used by a lot of subsequent backports), latter is a new feature which I
tried to avoid backport at first.

However I wasn't sure whether there will be problem without fde2a3882bd0
"bpf: support precision propagation in the presence of subprogs" that
propagates precision marks from callback back to caller, so I picked it
up anyway. Plus with it backported, stable aligns with upstream better,
thus makes commit ab5cfac139ab ("bpf: verify callbacks as if they are
called unknown number of times") easier to backport.

1.  5956f3011604 "veristat: add -t flag for adding BPF_F_TEST_STATE_FREQ program flag"
    - fails to apply, ignoring for now
2.  e0bf462276b6 "bpf: mark relevant stack slots scratched for register read instructions"
3.  407958a0e980 "bpf: encapsulate precision backtracking bookkeeping"
4.  d9439c21a9e4 "bpf: improve precision backtrack logging"
5.  1ef22b6865a7 "bpf: maintain bitmasks across all active frames in __mark_chain_precision"
6.  f655badf2a8f "bpf: fix propagate_precision() logic for inner frames"
7.  c50c0b57a515 "bpf: fix mark_all_scalars_precise use in mark_chain_precision"
8.  fde2a3882bd0 "bpf: support precision propagation in the presence of subprogs"
9.  3ef3d2177b1a "selftests/bpf: add precision propagation tests in the presence of subprogs"
    - dropped for now
10. c91ab90cea7a "selftests/bpf: revert iter test subprog precision workaround"
    - dropped for now


d84b1a6708ee "bpf: fix calculation of subseq_idx during precision backtracking"[6]
----------------------------------------------------------------------------------
Initially I missed this fix, which lead to backtracking bug when
running the reproducer in

  check_helper_call()
    update_loop_inline_state()
	  loop_flag_is_zero()
	    mark_chain_precision()
          __mark_chain_precision()
            backtrack_insn()
              !!(bt_reg_mask(bt) & BPF_REGMASK_ARGS) == true

Where the verifier log shows

  from 29 to 11: R1=100 R2=func(off=0,imm=0) R3=fp-16 R4=0 R10=fp0 fp-8=00000000 fp-16=57005
  ; bpf_loop(100, loop_callback, &context, 0);
  11: (85) call bpf_loop#181
  mark_precise: frame0: last_idx 11 first_idx 11
  mark_precise: frame0: parent state regs=r4 stack=:  R1_r=100 R2_r=func(off=0,imm=0) R3_r=fp-16 R4_r=P0 R10=fp0 fp-8=00000000 fp-16=57005
  mark_precise: frame0: last_idx 29 first_idx 28
  mark_precise: frame0: regs=r4 stack= before 29: (95) exit
  BUG regs 10
  mark_precise: frame0: last_idx 11 first_idx 11
  mark_precise: frame0: parent state regs=r1 stack=:  R1_r=P100 R2_r=func(off=0,imm=0) R3_r=fp-16 R4_r=P0 R10=fp0 fp-8=00000000 fp-16=57005
  mark_precise: frame0: last_idx 29 first_idx 28
  mark_precise: frame0: regs=r1 stack= before 29: (95) exit
  BUG regs 2


verify scalar ids mapping in regsafe()[7]
-----------------------------------------
Pulled for regsafe()-related changes, and also struct bpf_idset change
to make backporting commits easier.

1.  904e6ddf4133 "bpf: use scalar ids in mark_chain_precision()"
2.  dec020280373 "selftests/bpf: check if mark_chain_precision() follows scalar ids"
    - dropped for now
3.  1ffc85d9298e "bpf: verify scalar ids mapping in regsafe() using check_ids()"
4.  18b89265572b "selftests/bpf: verify that check_ids() is used for scalars in regsafe()"
    - dropped for now


exact states comparison for iterator convergence checks[8]
----------------------------------------------------------
Backport from the existing 6.6 backports[9].

> 1.  3c4e420cb653 ("bpf: move explored_state() closer to the beginning of verifier.c ")
>     - should apply as-is;
> 2.  4c97259abc9b ("bpf: extract same_callsites() as utility function ")
>     - should apply as-is;

  both applicable

> 3.  2793a8b015f7 ("bpf: exact states comparison for iterator convergence checks ")

  dropped tools/testing/selftests/bpf/progs/iters_task_vma.c change for
  now

>     - needs regs_exact() introduced/modified in:
>       - 4a95c85c9948 ("bpf: perform byte-by-byte comparison only when necessary in regsafe()")
>       - 4633a0068258 ("bpf: fix regs_exact() logic in regsafe() to remap IDs correctly")
>       - 1ffc85d9298e ("bpf: Verify scalar ids mapping in regsafe() using check_ids()")

  all picked up

>     - changes to process_iter_next_call() are not needed;

  dropped as suggested

>     - changes to regsafe() seem applicable;
>     - changes to stacksafe() seem applicable;

  while applicable, without d6fefa1105dac "bpf: Fix state pruning for
  STACK_DYNPTR stack slots" stacksafe() doesn't check the slot type. I
  didn't pick it up because the current patch-set is already quite large
  and it is arguably a different issue, but it would be better to have
  it as well.

>     - changes to func_states_equal():
>       - seem applicable, but there is a commit that removes
>         memset for idmap_scratch from func_states_equal(),
>         it is not necessary for this particular fix,
>         but is a safety fix in itself:
>         1ffc85d9298e ("bpf: Verify scalar ids mapping in regsafe() using check_ids()")

  picked up

>     - changes to is_state_visited():
>       - ignore iterator related changes, just add a new parameter for
>         states_equal() where necessary;
>       - change to visited states eviction heuristic is probably needed
>         (the hunk with "if (sl->miss_cnt > sl->hit_cnt * n + n)");

  included

>       - don't miss the hunk with "cur->dfs_depth = new->dfs_depth + 1;";

  included as well

> 4.  389ede06c297 ("selftests/bpf: tests with delayed read/precision makrs in loop body ")
>     [didn't look at this]
  dropped for now
> 5.  2a0992829ea3 ("bpf: correct loop detection for iterators convergence ")
>     - looks like it could be applied with minimal changes;

  indeed, only need to drop the changes under
  "if (is_iter_next_insn(...))" within is_state_visited()

> 6.  64870feebecb ("selftests/bpf: test if state loops are detected in a tricky case ")
>     [didn't look at this]
  dropped for now
> 7.  b4d8239534fd ("bpf: print full verifier states on infinite loop detection ")
>     [didn't look at this]
  applicable with just minor context difference
> 8.  977bc146d4eb ("selftests/bpf: track tcp payload offset as scalar in xdp_synproxy ")
>     [didn't look at this]
  picked but not tested yet
> 9.  87eb0152bcc1 ("selftests/bpf: track string payload offset as scalar in strobemeta ")
>     [didn't look at this]
  picked but not tested yet


verify callbacks as if they are called unknown number of times[10]
------------------------------------------------------------------
Again, backport from the existing 6.6 backports[9].

> 10. 683b96f9606a ("bpf: extract __check_reg_arg() utility function ")
>     A small refactoring, shouldn't be hard to port.
> 11. 58124a98cb8e ("bpf: extract setup_func_entry() utility function ")
>     A small refactoring, shouldn't be hard to port.

  both applicable

> 12. ab5cfac139ab ("bpf: verify callbacks as if they are called unknown number of times ")

  dropped all selftest changes for now.

>     - backtrack_insn() lacks Andrii's refactoring that introduces 'struct backtrack_state',
>       technically it shouldn't be hard to repeat patch logic w/o that refactoring,
>       but this would lead to further divergence with upstream;

  agree, without 407958a0e980 "bpf: encapsulate precision backtracking
  bookkeeping" it really gets quite painful to backport this and other
  previous patches, so ended up getting the while patch-set[4]

>     - backtrack_insn() lacks subseq_idx parameter;

  parameter is added with fde2a3882bd0 "bpf: support precision
  propagation in the presence of subprogs" from [4] backported

>     - __check_func_call() seems similar enough, so shouldn't be a big problem;

  is_callback_calling_kfunc()/is_sync_callback_calling_kfunc() does not
  exists because commit 5d92ddc3de1b ("bpf: Add callback validation to
  kfunc verifier logic") is not present, so instead of 

	if (bpf_pseudo_kfunc_call(insn) &&
	    !is_sync_callback_calling_kfunc(insn->imm))
		verbose(env, "verifier bug: kfunc %s#%d not marked as callback-calling\n",
			func_id_name(insn->imm), insn->imm);

  I used

	if (bpf_pseudo_kfunc_call(insn)) {
		verbose(env, "verifier bug: kfunc %s#%d with callback is not supported\n",
			func_id_name(insn->imm), insn->imm);

>     - prepare_func_exit() similar enough;
>     - check_helper_call() similar enough;

  both applicable

>     - check_kfunc_call() it looks like kfunc KF_bpf_rbtree_add_impl
>       (the only kfunc that calls a callback) is not in the kernel yet,
>       so changes to check_kfunc_call are not necessary;

  changes dropped as suggested

>     - visit_insn() similar enough;

  applicable

>     - is_state_visited() needs a 'skip_inf_loop_check' label,
>       but otherwise seems applicable;

  several changes to deal with commit 06accc8779c1d ("bpf: add support for
  open-coded iterator loops") not present in stable 6.1:
  - context difference because there no "if (is_iter_next_insn(env,
	insn_idx))" block
  - dropped !iter_active_depths_differ() check in infinite-loop detection
  - added skip_inf_loop_check label along with the hit label, borrowed
	from commit 06accc8779c1d ("bpf: add support for open-coded iterator
	loops")

> 13. 958465e217db ("selftests/bpf: tests for iterating callbacks ")
>     - tools/testing/selftests/bpf/prog_tests/verifier.c is not in 6.1,
>       so adding a custom progs/*.c driver program would be necessary;

  indeed, will try to backport prog_tests/verifier.c next, dropping for
  now

> 14. cafe2c21508a ("bpf: widening for callback iterators ")

  dropped all selftest changes for now.

>     - technically, this is not necessary from safety point of view,
>       but exact states comparison is very restrictive,
>       so porting this is probably a good idea;
>     - shouldn't be hard to port if widen_imprecise_scalars() and co
>       are already ported;
  
  quite easy to backport, picked up as suggested

> 15. 9f3330aa644d ("selftests/bpf: test widening for iterating callbacks ")
>     [didn't look at this]
  dropped for now
> 16. bb124da69c47 ("bpf: keep track of max number of bpf_loop callback iterations ")
>     - this is more "nice to have" patch, it fallbacks to enumeration
>       of every iteration step for bpf_loop, if exact match/widening
>       logic does not converge;
>     - shouldn't be hard to port;

  picked up as suggested

>     - note also the following bug fix for this commit:
>       https://lore.kernel.org/bpf/20240222154121.6991-1-eddyz87@xxxxxxxxx/

  also picked up

> 17. 57e2a52deeb1 ("selftests/bpf: check if max number of bpf_loop iterations is tracked ")
>     [didn't look at this]
  dropped for now


With all the above applied, the verifier no correctly rejected the
reproducer.

  from 16 to 20: frame1: R1_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff)) R2=fp-16 R10=fp0 cb
  20: frame1: R1_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff)) R2=fp-16 R10=fp0 cb
  ; if (bpf_probe_read_user(ctx->buf, 8, (void*)(0xBADC0FFEE))) {
  20: (79) r1 = *(u64 *)(r2 +0)         ; frame1: R1_w=57005 R2=fp-16 cb
  ; if (bpf_probe_read_user(ctx->buf, 8, (void*)(0xBADC0FFEE))) {
  21: (b7) r2 = 8                       ; frame1: R2_w=8 cb
  22: (18) r3 = 0xbadc0ffee             ; frame1: R3_w=50159747054 cb
  24: (85) call bpf_probe_read_user#112
  R1 type=scalar expected=fp, pkt, pkt_meta, map_key, map_value, mem, alloc_mem, buf

> Also note the following patch from Alexei, relaxing exact states
> comparison a bit:
> https://lore.kernel.org/bpf/20240306031929.42666-3-alexei.starovoitov@xxxxxxxxx/
> 
> Hope this helps.

It helped greatly :)

> Sounds like a lot of work.
> Feel free to ask any questions about the patch-sets.

Next I'll try to get the selftests backported and make sure they passes,
and very likely will need your help if there's failure. Will post a
follow-up on that.

Thanks,
Shung-Hsi

1: https://lore.kernel.org/r/20221209135733.28851-1-eddyz87@xxxxxxxxx/
2: https://lore.kernel.org/r/20221223054921.958283-1-andrii@xxxxxxxxxx/
3: https://lore.kernel.org/r/20230310060149.625887-1-andrii@xxxxxxxxxx/
4: https://lore.kernel.org/r/20230505043317.3629845-1-andrii@xxxxxxxxxx/
5: https://lore.kernel.org/r/20230417222134.359714-1-yhs@xxxxxx/
6: https://lore.kernel.org/r/20230515180710.1535018-1-andrii@xxxxxxxxxx/
7: https://lore.kernel.org/r/20230613153824.3324830-1-eddyz87@xxxxxxxxx/
8: https://lore.kernel.org/r/20231024000917.12153-1-eddyz87@xxxxxxxxx/
9: https://lore.kernel.org/stable/20240125001554.25287-1-eddyz87@xxxxxxxxx/
10: https://lore.kernel.org/r/20231121020701.26440-1-eddyz87@xxxxxxxxx/




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux