xref: /linux/tools/testing/selftests/bpf/progs/sock_ops_get_sk.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*04013c3cSJiayuan Chen // SPDX-License-Identifier: GPL-2.0
2*04013c3cSJiayuan Chen 
3*04013c3cSJiayuan Chen #include "vmlinux.h"
4*04013c3cSJiayuan Chen #include <bpf/bpf_helpers.h>
5*04013c3cSJiayuan Chen #include "bpf_misc.h"
6*04013c3cSJiayuan Chen 
7*04013c3cSJiayuan Chen /*
8*04013c3cSJiayuan Chen  * Test the SOCK_OPS_GET_SK() and SOCK_OPS_GET_FIELD() macros in
9*04013c3cSJiayuan Chen  * sock_ops_convert_ctx_access() when dst_reg == src_reg.
10*04013c3cSJiayuan Chen  *
11*04013c3cSJiayuan Chen  * When dst_reg == src_reg, the macros borrow a temporary register to load
12*04013c3cSJiayuan Chen  * is_fullsock / is_locked_tcp_sock, because dst_reg holds the ctx pointer
13*04013c3cSJiayuan Chen  * and cannot be clobbered before ctx->sk / ctx->field is read. If
14*04013c3cSJiayuan Chen  * is_fullsock == 0 (e.g., TCP_NEW_SYN_RECV with a request_sock), the macro
15*04013c3cSJiayuan Chen  * must still zero dst_reg so the verifier's PTR_TO_SOCKET_OR_NULL /
16*04013c3cSJiayuan Chen  * SCALAR_VALUE type is correct at runtime. A missing clear leaves a stale
17*04013c3cSJiayuan Chen  * ctx pointer in dst_reg that passes NULL checks (GET_SK) or leaks a kernel
18*04013c3cSJiayuan Chen  * address as a scalar (GET_FIELD).
19*04013c3cSJiayuan Chen  *
20*04013c3cSJiayuan Chen  * When dst_reg != src_reg, dst_reg itself is used to load is_fullsock, so
21*04013c3cSJiayuan Chen  * the JEQ (dst_reg == 0) naturally leaves it zeroed on the !fullsock path.
22*04013c3cSJiayuan Chen  */
23*04013c3cSJiayuan Chen 
24*04013c3cSJiayuan Chen int bug_detected;
25*04013c3cSJiayuan Chen int null_seen;
26*04013c3cSJiayuan Chen 
27*04013c3cSJiayuan Chen SEC("sockops")
28*04013c3cSJiayuan Chen __naked void sock_ops_get_sk_same_reg(void)
29*04013c3cSJiayuan Chen {
30*04013c3cSJiayuan Chen 	asm volatile (
31*04013c3cSJiayuan Chen 		"r7 = *(u32 *)(r1 + %[is_fullsock_off]);"
32*04013c3cSJiayuan Chen 		"r1 = *(u64 *)(r1 + %[sk_off]);"
33*04013c3cSJiayuan Chen 		"if r7 != 0 goto 2f;"
34*04013c3cSJiayuan Chen 		"if r1 == 0 goto 1f;"
35*04013c3cSJiayuan Chen 		"r1 = %[bug_detected] ll;"
36*04013c3cSJiayuan Chen 		"r2 = 1;"
37*04013c3cSJiayuan Chen 		"*(u32 *)(r1 + 0) = r2;"
38*04013c3cSJiayuan Chen 		"goto 2f;"
39*04013c3cSJiayuan Chen 	"1:"
40*04013c3cSJiayuan Chen 		"r1 = %[null_seen] ll;"
41*04013c3cSJiayuan Chen 		"r2 = 1;"
42*04013c3cSJiayuan Chen 		"*(u32 *)(r1 + 0) = r2;"
43*04013c3cSJiayuan Chen 	"2:"
44*04013c3cSJiayuan Chen 		"r0 = 1;"
45*04013c3cSJiayuan Chen 		"exit;"
46*04013c3cSJiayuan Chen 		:
47*04013c3cSJiayuan Chen 		: __imm_const(is_fullsock_off, offsetof(struct bpf_sock_ops, is_fullsock)),
48*04013c3cSJiayuan Chen 		  __imm_const(sk_off, offsetof(struct bpf_sock_ops, sk)),
49*04013c3cSJiayuan Chen 		  __imm_addr(bug_detected),
50*04013c3cSJiayuan Chen 		  __imm_addr(null_seen)
51*04013c3cSJiayuan Chen 		: __clobber_all);
52*04013c3cSJiayuan Chen }
53*04013c3cSJiayuan Chen 
54*04013c3cSJiayuan Chen /* SOCK_OPS_GET_FIELD: same-register, is_locked_tcp_sock == 0 path. */
55*04013c3cSJiayuan Chen int field_bug_detected;
56*04013c3cSJiayuan Chen int field_null_seen;
57*04013c3cSJiayuan Chen 
58*04013c3cSJiayuan Chen SEC("sockops")
59*04013c3cSJiayuan Chen __naked void sock_ops_get_field_same_reg(void)
60*04013c3cSJiayuan Chen {
61*04013c3cSJiayuan Chen 	asm volatile (
62*04013c3cSJiayuan Chen 		"r7 = *(u32 *)(r1 + %[is_fullsock_off]);"
63*04013c3cSJiayuan Chen 		"r1 = *(u32 *)(r1 + %[snd_cwnd_off]);"
64*04013c3cSJiayuan Chen 		"if r7 != 0 goto 2f;"
65*04013c3cSJiayuan Chen 		"if r1 == 0 goto 1f;"
66*04013c3cSJiayuan Chen 		"r1 = %[field_bug_detected] ll;"
67*04013c3cSJiayuan Chen 		"r2 = 1;"
68*04013c3cSJiayuan Chen 		"*(u32 *)(r1 + 0) = r2;"
69*04013c3cSJiayuan Chen 		"goto 2f;"
70*04013c3cSJiayuan Chen 	"1:"
71*04013c3cSJiayuan Chen 		"r1 = %[field_null_seen] ll;"
72*04013c3cSJiayuan Chen 		"r2 = 1;"
73*04013c3cSJiayuan Chen 		"*(u32 *)(r1 + 0) = r2;"
74*04013c3cSJiayuan Chen 	"2:"
75*04013c3cSJiayuan Chen 		"r0 = 1;"
76*04013c3cSJiayuan Chen 		"exit;"
77*04013c3cSJiayuan Chen 		:
78*04013c3cSJiayuan Chen 		: __imm_const(is_fullsock_off, offsetof(struct bpf_sock_ops, is_fullsock)),
79*04013c3cSJiayuan Chen 		  __imm_const(snd_cwnd_off, offsetof(struct bpf_sock_ops, snd_cwnd)),
80*04013c3cSJiayuan Chen 		  __imm_addr(field_bug_detected),
81*04013c3cSJiayuan Chen 		  __imm_addr(field_null_seen)
82*04013c3cSJiayuan Chen 		: __clobber_all);
83*04013c3cSJiayuan Chen }
84*04013c3cSJiayuan Chen 
85*04013c3cSJiayuan Chen /* SOCK_OPS_GET_SK: different-register, is_fullsock == 0 path. */
86*04013c3cSJiayuan Chen int diff_reg_bug_detected;
87*04013c3cSJiayuan Chen int diff_reg_null_seen;
88*04013c3cSJiayuan Chen 
89*04013c3cSJiayuan Chen SEC("sockops")
90*04013c3cSJiayuan Chen __naked void sock_ops_get_sk_diff_reg(void)
91*04013c3cSJiayuan Chen {
92*04013c3cSJiayuan Chen 	asm volatile (
93*04013c3cSJiayuan Chen 		"r7 = r1;"
94*04013c3cSJiayuan Chen 		"r6 = *(u32 *)(r7 + %[is_fullsock_off]);"
95*04013c3cSJiayuan Chen 		"r2 = *(u64 *)(r7 + %[sk_off]);"
96*04013c3cSJiayuan Chen 		"if r6 != 0 goto 2f;"
97*04013c3cSJiayuan Chen 		"if r2 == 0 goto 1f;"
98*04013c3cSJiayuan Chen 		"r1 = %[diff_reg_bug_detected] ll;"
99*04013c3cSJiayuan Chen 		"r3 = 1;"
100*04013c3cSJiayuan Chen 		"*(u32 *)(r1 + 0) = r3;"
101*04013c3cSJiayuan Chen 		"goto 2f;"
102*04013c3cSJiayuan Chen 	"1:"
103*04013c3cSJiayuan Chen 		"r1 = %[diff_reg_null_seen] ll;"
104*04013c3cSJiayuan Chen 		"r3 = 1;"
105*04013c3cSJiayuan Chen 		"*(u32 *)(r1 + 0) = r3;"
106*04013c3cSJiayuan Chen 	"2:"
107*04013c3cSJiayuan Chen 		"r0 = 1;"
108*04013c3cSJiayuan Chen 		"exit;"
109*04013c3cSJiayuan Chen 		:
110*04013c3cSJiayuan Chen 		: __imm_const(is_fullsock_off, offsetof(struct bpf_sock_ops, is_fullsock)),
111*04013c3cSJiayuan Chen 		  __imm_const(sk_off, offsetof(struct bpf_sock_ops, sk)),
112*04013c3cSJiayuan Chen 		  __imm_addr(diff_reg_bug_detected),
113*04013c3cSJiayuan Chen 		  __imm_addr(diff_reg_null_seen)
114*04013c3cSJiayuan Chen 		: __clobber_all);
115*04013c3cSJiayuan Chen }
116*04013c3cSJiayuan Chen 
117*04013c3cSJiayuan Chen char _license[] SEC("license") = "GPL";
118