[PATCH bpf-next 2/4] bpf: Mark pending zero extension of arena ptrs before pruning a state

Daniel Borkmann <[email protected]>
Newsgroups org.kernel.vger.bpf
Message-ID <[email protected]>
bpf_mark_live_subregs_zext() marks the definitions of the registers live
at a pruning point so that a subreg_def whose only 64-bit read lies beyond
the prune is not left unmarked, but only SCALAR_VALUE currently.

PTR_TO_ARENA is the one other type that carries a real subreg_def and can
be read as a full 64-bit value: the addr_space_cast to arena (cast_kern)
records the cast insn in subreg_def, and the later 64-bit use (a load,
store or ALU64 with the pointer as source) is what marks it. The arena
access computes its address as pointer + arena_vm_start and trusts the
pointer's upper half to be zero, e.g. an indexed 'llgc %dst,off(%src,%arena)'
on s390 or a 'src + arena_vm_start' add on riscv64 and x86-64.

On x86-64 and riscv64 that upper half is cleared regardless of the mark:
x86-64 zero extends natively, and the riscv64 JIT emits its own zextw for
the cast. On a pure bpf_jit_needs_zext() architecture such as s390 the
cast_kern emits nothing and relies solely on the mark driven BPF_ZEXT_REG.
Thus, also mark the definitions of live PTR_TO_ARENA registers.

Fixes: 107e16979905 ("bpf: disable and remove registers chain based liveness")
Reported-by: STAR Labs SG <[email protected]>
Signed-off-by: Daniel Borkmann <[email protected]>
---
 kernel/bpf/verifier.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index e62b350b37af..4de9b464a9fc 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3172,11 +3172,14 @@ static void mark_insn_zext(struct bpf_verifier_env *env,
  * which is only ever read as a sub-register also gets its definition marked,
  * at the cost of a zero extension that is not needed.
  *
- * Only scalars are considered since a live_regs_before bit does not imply that
- * the register holds a readable value: the caller saved regs of a frame below
+ * Scalars and arena pointers are considered, the two types that carry a
+ * subreg_def and can still be read as a full 64-bit value past this point.
+ * The arena case matters on a pure bpf_jit_needs_zext() architecture. Other
+ * types are skipped since a live_regs_before bit does not imply that the
+ * register holds a readable value: the caller saved regs of a frame below
  * the current one are clobbered to NOT_INIT at the call while keeping the
- * subreg_def of the call insn. Such a definition must not be marked, the call
- * insn has no destination register to zero extend.
+ * subreg_def of the call insn. Such a definition must not be marked, the
+ * call insn has no destination register to zero extend.
  */
 void bpf_mark_live_subregs_zext(struct bpf_verifier_env *env,
 				struct bpf_verifier_state *vstate)
@@ -3192,7 +3195,8 @@ void bpf_mark_live_subregs_zext(struct bpf_verifier_env *env,
 		for (j = 0; j < BPF_REG_FP; j++) {
 			if (!(live_regs & BIT(j)))
 				continue;
-			if (func->regs[j].type != SCALAR_VALUE)
+			if (func->regs[j].type != SCALAR_VALUE &&
+			    func->regs[j].type != PTR_TO_ARENA)
 				continue;
 			mark_insn_zext(env, &func->regs[j]);
 		}
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.