When a BPF_PROG_TYPE_SOCK_OPS program reads a tcp_sock-backed context field (e.g. ctx->snd_ssthresh) or ctx->sk using the same register for source and destination, SOCK_OPS_GET_FIELD() and SOCK_OPS_GET_SK() load is_locked_tcp_sock/is_fullsock into a scratch register rather than into dst_reg. On the guard-failure branch the macro only restores the scratch register before falling through, leaving dst_reg holding the unchanged context pointer. Callers expect dst_reg to read as a scalar 0 when the guard fails. Instead the BPF program sees a kernel heap address, which the verifier has already typed as a scalar, giving a narrow kernel pointer leak. Clang does not emit the dst == src pattern for normal C ctx field reads, but it is reachable via inline asm and hand-written BPF. Add an explicit BPF_MOV64_IMM(dst_reg, 0) on the failure path in both macros and bump the success-path BPF_JMP_A() to skip over it. Found via AST-based call-graph analysis using sqry. Fixes: fd09af010788 ("bpf: sock_ops ctx access may stomp registers in corner case") Fixes: 84f44df664e9 ("bpf: sock_ops sk access may stomp registers when dst_reg = src_reg") Cc: stable@vger.kernel.org Signed-off-by: Werner Kasselman --- net/core/filter.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 78b548158fb0..53ce06ed4a88 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -10581,10 +10581,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, si->dst_reg, si->dst_reg, \ offsetof(OBJ, OBJ_FIELD)); \ if (si->dst_reg == si->src_reg) { \ - *insn++ = BPF_JMP_A(1); \ + *insn++ = BPF_JMP_A(2); \ *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \ offsetof(struct bpf_sock_ops_kern, \ temp)); \ + *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \ } \ } while (0) @@ -10618,10 +10619,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, si->dst_reg, si->src_reg, \ offsetof(struct bpf_sock_ops_kern, sk));\ if (si->dst_reg == si->src_reg) { \ - *insn++ = BPF_JMP_A(1); \ + *insn++ = BPF_JMP_A(2); \ *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \ offsetof(struct bpf_sock_ops_kern, \ temp)); \ + *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \ } \ } while (0) -- 2.43.0