xref: /linux/tools/testing/selftests/bpf/prog_tests/sock_post_bind.c (revision 25768de50b1f2dbb6ea44bd5148a87fe2c9c3688)
1*94682d6aSJordan Rife // SPDX-License-Identifier: GPL-2.0
2*94682d6aSJordan Rife #include <linux/bpf.h>
3*94682d6aSJordan Rife #include <test_progs.h>
4*94682d6aSJordan Rife #include "cgroup_helpers.h"
5*94682d6aSJordan Rife 
6*94682d6aSJordan Rife #define TEST_NS "sock_post_bind"
7*94682d6aSJordan Rife 
8*94682d6aSJordan Rife static char bpf_log_buf[4096];
9*94682d6aSJordan Rife 
10*94682d6aSJordan Rife static struct sock_post_bind_test {
11*94682d6aSJordan Rife 	const char			*descr;
12*94682d6aSJordan Rife 	/* BPF prog properties */
13*94682d6aSJordan Rife 	const struct bpf_insn		insns[64];
14*94682d6aSJordan Rife 	enum bpf_attach_type		attach_type;
15*94682d6aSJordan Rife 	enum bpf_attach_type		expected_attach_type;
16*94682d6aSJordan Rife 	/* Socket properties */
17*94682d6aSJordan Rife 	int				domain;
18*94682d6aSJordan Rife 	int				type;
19*94682d6aSJordan Rife 	/* Endpoint to bind() to */
20*94682d6aSJordan Rife 	const char *ip;
21*94682d6aSJordan Rife 	unsigned short port;
22*94682d6aSJordan Rife 	unsigned short port_retry;
23*94682d6aSJordan Rife 
24*94682d6aSJordan Rife 	/* Expected test result */
25*94682d6aSJordan Rife 	enum {
26*94682d6aSJordan Rife 		ATTACH_REJECT,
27*94682d6aSJordan Rife 		BIND_REJECT,
28*94682d6aSJordan Rife 		SUCCESS,
29*94682d6aSJordan Rife 		RETRY_SUCCESS,
30*94682d6aSJordan Rife 		RETRY_REJECT
31*94682d6aSJordan Rife 	} result;
32*94682d6aSJordan Rife } tests[] = {
33*94682d6aSJordan Rife 	{
34*94682d6aSJordan Rife 		.descr = "attach type mismatch bind4 vs bind6",
35*94682d6aSJordan Rife 		.insns = {
36*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
37*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
38*94682d6aSJordan Rife 		},
39*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
40*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET6_POST_BIND,
41*94682d6aSJordan Rife 		.result = ATTACH_REJECT,
42*94682d6aSJordan Rife 	},
43*94682d6aSJordan Rife 	{
44*94682d6aSJordan Rife 		.descr = "attach type mismatch bind6 vs bind4",
45*94682d6aSJordan Rife 		.insns = {
46*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
47*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
48*94682d6aSJordan Rife 		},
49*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
50*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET4_POST_BIND,
51*94682d6aSJordan Rife 		.result = ATTACH_REJECT,
52*94682d6aSJordan Rife 	},
53*94682d6aSJordan Rife 	{
54*94682d6aSJordan Rife 		.descr = "attach type mismatch default vs bind4",
55*94682d6aSJordan Rife 		.insns = {
56*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
57*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
58*94682d6aSJordan Rife 		},
59*94682d6aSJordan Rife 		.expected_attach_type = 0,
60*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET4_POST_BIND,
61*94682d6aSJordan Rife 		.result = ATTACH_REJECT,
62*94682d6aSJordan Rife 	},
63*94682d6aSJordan Rife 	{
64*94682d6aSJordan Rife 		.descr = "attach type mismatch bind6 vs sock_create",
65*94682d6aSJordan Rife 		.insns = {
66*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
67*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
68*94682d6aSJordan Rife 		},
69*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
70*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
71*94682d6aSJordan Rife 		.result = ATTACH_REJECT,
72*94682d6aSJordan Rife 	},
73*94682d6aSJordan Rife 	{
74*94682d6aSJordan Rife 		.descr = "bind4 reject all",
75*94682d6aSJordan Rife 		.insns = {
76*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 0),
77*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
78*94682d6aSJordan Rife 		},
79*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
80*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET4_POST_BIND,
81*94682d6aSJordan Rife 		.domain = AF_INET,
82*94682d6aSJordan Rife 		.type = SOCK_STREAM,
83*94682d6aSJordan Rife 		.ip = "0.0.0.0",
84*94682d6aSJordan Rife 		.result = BIND_REJECT,
85*94682d6aSJordan Rife 	},
86*94682d6aSJordan Rife 	{
87*94682d6aSJordan Rife 		.descr = "bind6 reject all",
88*94682d6aSJordan Rife 		.insns = {
89*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 0),
90*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
91*94682d6aSJordan Rife 		},
92*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
93*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET6_POST_BIND,
94*94682d6aSJordan Rife 		.domain = AF_INET6,
95*94682d6aSJordan Rife 		.type = SOCK_STREAM,
96*94682d6aSJordan Rife 		.ip = "::",
97*94682d6aSJordan Rife 		.result = BIND_REJECT,
98*94682d6aSJordan Rife 	},
99*94682d6aSJordan Rife 	{
100*94682d6aSJordan Rife 		.descr = "bind6 deny specific IP & port",
101*94682d6aSJordan Rife 		.insns = {
102*94682d6aSJordan Rife 			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
103*94682d6aSJordan Rife 
104*94682d6aSJordan Rife 			/* if (ip == expected && port == expected) */
105*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
106*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_ip6[3])),
107*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
108*94682d6aSJordan Rife 				    __bpf_constant_ntohl(0x00000001), 4),
109*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
110*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_port)),
111*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
112*94682d6aSJordan Rife 
113*94682d6aSJordan Rife 			/* return DENY; */
114*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 0),
115*94682d6aSJordan Rife 			BPF_JMP_A(1),
116*94682d6aSJordan Rife 
117*94682d6aSJordan Rife 			/* else return ALLOW; */
118*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
119*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
120*94682d6aSJordan Rife 		},
121*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
122*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET6_POST_BIND,
123*94682d6aSJordan Rife 		.domain = AF_INET6,
124*94682d6aSJordan Rife 		.type = SOCK_STREAM,
125*94682d6aSJordan Rife 		.ip = "::1",
126*94682d6aSJordan Rife 		.port = 8193,
127*94682d6aSJordan Rife 		.result = BIND_REJECT,
128*94682d6aSJordan Rife 	},
129*94682d6aSJordan Rife 	{
130*94682d6aSJordan Rife 		.descr = "bind4 allow specific IP & port",
131*94682d6aSJordan Rife 		.insns = {
132*94682d6aSJordan Rife 			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
133*94682d6aSJordan Rife 
134*94682d6aSJordan Rife 			/* if (ip == expected && port == expected) */
135*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
136*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_ip4)),
137*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
138*94682d6aSJordan Rife 				    __bpf_constant_ntohl(0x7F000001), 4),
139*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
140*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_port)),
141*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
142*94682d6aSJordan Rife 
143*94682d6aSJordan Rife 			/* return ALLOW; */
144*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
145*94682d6aSJordan Rife 			BPF_JMP_A(1),
146*94682d6aSJordan Rife 
147*94682d6aSJordan Rife 			/* else return DENY; */
148*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 0),
149*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
150*94682d6aSJordan Rife 		},
151*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
152*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET4_POST_BIND,
153*94682d6aSJordan Rife 		.domain = AF_INET,
154*94682d6aSJordan Rife 		.type = SOCK_STREAM,
155*94682d6aSJordan Rife 		.ip = "127.0.0.1",
156*94682d6aSJordan Rife 		.port = 4098,
157*94682d6aSJordan Rife 		.result = SUCCESS,
158*94682d6aSJordan Rife 	},
159*94682d6aSJordan Rife 	{
160*94682d6aSJordan Rife 		.descr = "bind4 deny specific IP & port of TCP, and retry",
161*94682d6aSJordan Rife 		.insns = {
162*94682d6aSJordan Rife 			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
163*94682d6aSJordan Rife 
164*94682d6aSJordan Rife 			/* if (ip == expected && port == expected) */
165*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
166*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_ip4)),
167*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
168*94682d6aSJordan Rife 				    __bpf_constant_ntohl(0x7F000001), 4),
169*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
170*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_port)),
171*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
172*94682d6aSJordan Rife 
173*94682d6aSJordan Rife 			/* return DENY; */
174*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 0),
175*94682d6aSJordan Rife 			BPF_JMP_A(1),
176*94682d6aSJordan Rife 
177*94682d6aSJordan Rife 			/* else return ALLOW; */
178*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
179*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
180*94682d6aSJordan Rife 		},
181*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
182*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET4_POST_BIND,
183*94682d6aSJordan Rife 		.domain = AF_INET,
184*94682d6aSJordan Rife 		.type = SOCK_STREAM,
185*94682d6aSJordan Rife 		.ip = "127.0.0.1",
186*94682d6aSJordan Rife 		.port = 4098,
187*94682d6aSJordan Rife 		.port_retry = 5000,
188*94682d6aSJordan Rife 		.result = RETRY_SUCCESS,
189*94682d6aSJordan Rife 	},
190*94682d6aSJordan Rife 	{
191*94682d6aSJordan Rife 		.descr = "bind4 deny specific IP & port of UDP, and retry",
192*94682d6aSJordan Rife 		.insns = {
193*94682d6aSJordan Rife 			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
194*94682d6aSJordan Rife 
195*94682d6aSJordan Rife 			/* if (ip == expected && port == expected) */
196*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
197*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_ip4)),
198*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
199*94682d6aSJordan Rife 				    __bpf_constant_ntohl(0x7F000001), 4),
200*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
201*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_port)),
202*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
203*94682d6aSJordan Rife 
204*94682d6aSJordan Rife 			/* return DENY; */
205*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 0),
206*94682d6aSJordan Rife 			BPF_JMP_A(1),
207*94682d6aSJordan Rife 
208*94682d6aSJordan Rife 			/* else return ALLOW; */
209*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
210*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
211*94682d6aSJordan Rife 		},
212*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
213*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET4_POST_BIND,
214*94682d6aSJordan Rife 		.domain = AF_INET,
215*94682d6aSJordan Rife 		.type = SOCK_DGRAM,
216*94682d6aSJordan Rife 		.ip = "127.0.0.1",
217*94682d6aSJordan Rife 		.port = 4098,
218*94682d6aSJordan Rife 		.port_retry = 5000,
219*94682d6aSJordan Rife 		.result = RETRY_SUCCESS,
220*94682d6aSJordan Rife 	},
221*94682d6aSJordan Rife 	{
222*94682d6aSJordan Rife 		.descr = "bind6 deny specific IP & port, and retry",
223*94682d6aSJordan Rife 		.insns = {
224*94682d6aSJordan Rife 			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
225*94682d6aSJordan Rife 
226*94682d6aSJordan Rife 			/* if (ip == expected && port == expected) */
227*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
228*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_ip6[3])),
229*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
230*94682d6aSJordan Rife 				    __bpf_constant_ntohl(0x00000001), 4),
231*94682d6aSJordan Rife 			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
232*94682d6aSJordan Rife 				    offsetof(struct bpf_sock, src_port)),
233*94682d6aSJordan Rife 			BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
234*94682d6aSJordan Rife 
235*94682d6aSJordan Rife 			/* return DENY; */
236*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 0),
237*94682d6aSJordan Rife 			BPF_JMP_A(1),
238*94682d6aSJordan Rife 
239*94682d6aSJordan Rife 			/* else return ALLOW; */
240*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
241*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
242*94682d6aSJordan Rife 		},
243*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
244*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET6_POST_BIND,
245*94682d6aSJordan Rife 		.domain = AF_INET6,
246*94682d6aSJordan Rife 		.type = SOCK_STREAM,
247*94682d6aSJordan Rife 		.ip = "::1",
248*94682d6aSJordan Rife 		.port = 8193,
249*94682d6aSJordan Rife 		.port_retry = 9000,
250*94682d6aSJordan Rife 		.result = RETRY_SUCCESS,
251*94682d6aSJordan Rife 	},
252*94682d6aSJordan Rife 	{
253*94682d6aSJordan Rife 		.descr = "bind4 allow all",
254*94682d6aSJordan Rife 		.insns = {
255*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
256*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
257*94682d6aSJordan Rife 		},
258*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
259*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET4_POST_BIND,
260*94682d6aSJordan Rife 		.domain = AF_INET,
261*94682d6aSJordan Rife 		.type = SOCK_STREAM,
262*94682d6aSJordan Rife 		.ip = "0.0.0.0",
263*94682d6aSJordan Rife 		.result = SUCCESS,
264*94682d6aSJordan Rife 	},
265*94682d6aSJordan Rife 	{
266*94682d6aSJordan Rife 		.descr = "bind6 allow all",
267*94682d6aSJordan Rife 		.insns = {
268*94682d6aSJordan Rife 			BPF_MOV64_IMM(BPF_REG_0, 1),
269*94682d6aSJordan Rife 			BPF_EXIT_INSN(),
270*94682d6aSJordan Rife 		},
271*94682d6aSJordan Rife 		.expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
272*94682d6aSJordan Rife 		.attach_type = BPF_CGROUP_INET6_POST_BIND,
273*94682d6aSJordan Rife 		.domain = AF_INET6,
274*94682d6aSJordan Rife 		.type = SOCK_STREAM,
275*94682d6aSJordan Rife 		.ip = "::",
276*94682d6aSJordan Rife 		.result = SUCCESS,
277*94682d6aSJordan Rife 	},
278*94682d6aSJordan Rife };
279*94682d6aSJordan Rife 
280*94682d6aSJordan Rife static int load_prog(const struct bpf_insn *insns,
281*94682d6aSJordan Rife 		     enum bpf_attach_type expected_attach_type)
282*94682d6aSJordan Rife {
283*94682d6aSJordan Rife 	LIBBPF_OPTS(bpf_prog_load_opts, opts,
284*94682d6aSJordan Rife 		    .expected_attach_type = expected_attach_type,
285*94682d6aSJordan Rife 		    .log_level = 2,
286*94682d6aSJordan Rife 		    .log_buf = bpf_log_buf,
287*94682d6aSJordan Rife 		    .log_size = sizeof(bpf_log_buf),
288*94682d6aSJordan Rife 	);
289*94682d6aSJordan Rife 	int fd, insns_cnt = 0;
290*94682d6aSJordan Rife 
291*94682d6aSJordan Rife 	for (;
292*94682d6aSJordan Rife 	     insns[insns_cnt].code != (BPF_JMP | BPF_EXIT);
293*94682d6aSJordan Rife 	     insns_cnt++) {
294*94682d6aSJordan Rife 	}
295*94682d6aSJordan Rife 	insns_cnt++;
296*94682d6aSJordan Rife 
297*94682d6aSJordan Rife 	fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns,
298*94682d6aSJordan Rife 			   insns_cnt, &opts);
299*94682d6aSJordan Rife 	if (fd < 0)
300*94682d6aSJordan Rife 		fprintf(stderr, "%s\n", bpf_log_buf);
301*94682d6aSJordan Rife 
302*94682d6aSJordan Rife 	return fd;
303*94682d6aSJordan Rife }
304*94682d6aSJordan Rife 
305*94682d6aSJordan Rife static int bind_sock(int domain, int type, const char *ip,
306*94682d6aSJordan Rife 		     unsigned short port, unsigned short port_retry)
307*94682d6aSJordan Rife {
308*94682d6aSJordan Rife 	struct sockaddr_storage addr;
309*94682d6aSJordan Rife 	struct sockaddr_in6 *addr6;
310*94682d6aSJordan Rife 	struct sockaddr_in *addr4;
311*94682d6aSJordan Rife 	int sockfd = -1;
312*94682d6aSJordan Rife 	socklen_t len;
313*94682d6aSJordan Rife 	int res = SUCCESS;
314*94682d6aSJordan Rife 
315*94682d6aSJordan Rife 	sockfd = socket(domain, type, 0);
316*94682d6aSJordan Rife 	if (sockfd < 0)
317*94682d6aSJordan Rife 		goto err;
318*94682d6aSJordan Rife 
319*94682d6aSJordan Rife 	memset(&addr, 0, sizeof(addr));
320*94682d6aSJordan Rife 
321*94682d6aSJordan Rife 	if (domain == AF_INET) {
322*94682d6aSJordan Rife 		len = sizeof(struct sockaddr_in);
323*94682d6aSJordan Rife 		addr4 = (struct sockaddr_in *)&addr;
324*94682d6aSJordan Rife 		addr4->sin_family = domain;
325*94682d6aSJordan Rife 		addr4->sin_port = htons(port);
326*94682d6aSJordan Rife 		if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1)
327*94682d6aSJordan Rife 			goto err;
328*94682d6aSJordan Rife 	} else if (domain == AF_INET6) {
329*94682d6aSJordan Rife 		len = sizeof(struct sockaddr_in6);
330*94682d6aSJordan Rife 		addr6 = (struct sockaddr_in6 *)&addr;
331*94682d6aSJordan Rife 		addr6->sin6_family = domain;
332*94682d6aSJordan Rife 		addr6->sin6_port = htons(port);
333*94682d6aSJordan Rife 		if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1)
334*94682d6aSJordan Rife 			goto err;
335*94682d6aSJordan Rife 	} else {
336*94682d6aSJordan Rife 		goto err;
337*94682d6aSJordan Rife 	}
338*94682d6aSJordan Rife 
339*94682d6aSJordan Rife 	if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
340*94682d6aSJordan Rife 		/* sys_bind() may fail for different reasons, errno has to be
341*94682d6aSJordan Rife 		 * checked to confirm that BPF program rejected it.
342*94682d6aSJordan Rife 		 */
343*94682d6aSJordan Rife 		if (errno != EPERM)
344*94682d6aSJordan Rife 			goto err;
345*94682d6aSJordan Rife 		if (port_retry)
346*94682d6aSJordan Rife 			goto retry;
347*94682d6aSJordan Rife 		res = BIND_REJECT;
348*94682d6aSJordan Rife 		goto out;
349*94682d6aSJordan Rife 	}
350*94682d6aSJordan Rife 
351*94682d6aSJordan Rife 	goto out;
352*94682d6aSJordan Rife retry:
353*94682d6aSJordan Rife 	if (domain == AF_INET)
354*94682d6aSJordan Rife 		addr4->sin_port = htons(port_retry);
355*94682d6aSJordan Rife 	else
356*94682d6aSJordan Rife 		addr6->sin6_port = htons(port_retry);
357*94682d6aSJordan Rife 	if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
358*94682d6aSJordan Rife 		if (errno != EPERM)
359*94682d6aSJordan Rife 			goto err;
360*94682d6aSJordan Rife 		res = RETRY_REJECT;
361*94682d6aSJordan Rife 	} else {
362*94682d6aSJordan Rife 		res = RETRY_SUCCESS;
363*94682d6aSJordan Rife 	}
364*94682d6aSJordan Rife 	goto out;
365*94682d6aSJordan Rife err:
366*94682d6aSJordan Rife 	res = -1;
367*94682d6aSJordan Rife out:
368*94682d6aSJordan Rife 	close(sockfd);
369*94682d6aSJordan Rife 	return res;
370*94682d6aSJordan Rife }
371*94682d6aSJordan Rife 
372*94682d6aSJordan Rife static int run_test(int cgroup_fd, struct sock_post_bind_test *test)
373*94682d6aSJordan Rife {
374*94682d6aSJordan Rife 	int err, prog_fd, res, ret = 0;
375*94682d6aSJordan Rife 
376*94682d6aSJordan Rife 	prog_fd = load_prog(test->insns, test->expected_attach_type);
377*94682d6aSJordan Rife 	if (prog_fd < 0)
378*94682d6aSJordan Rife 		goto err;
379*94682d6aSJordan Rife 
380*94682d6aSJordan Rife 	err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
381*94682d6aSJordan Rife 	if (err < 0) {
382*94682d6aSJordan Rife 		if (test->result == ATTACH_REJECT)
383*94682d6aSJordan Rife 			goto out;
384*94682d6aSJordan Rife 		else
385*94682d6aSJordan Rife 			goto err;
386*94682d6aSJordan Rife 	}
387*94682d6aSJordan Rife 
388*94682d6aSJordan Rife 	res = bind_sock(test->domain, test->type, test->ip, test->port,
389*94682d6aSJordan Rife 			test->port_retry);
390*94682d6aSJordan Rife 	if (res > 0 && test->result == res)
391*94682d6aSJordan Rife 		goto out;
392*94682d6aSJordan Rife err:
393*94682d6aSJordan Rife 	ret = -1;
394*94682d6aSJordan Rife out:
395*94682d6aSJordan Rife 	/* Detaching w/o checking return code: best effort attempt. */
396*94682d6aSJordan Rife 	if (prog_fd != -1)
397*94682d6aSJordan Rife 		bpf_prog_detach(cgroup_fd, test->attach_type);
398*94682d6aSJordan Rife 	close(prog_fd);
399*94682d6aSJordan Rife 	return ret;
400*94682d6aSJordan Rife }
401*94682d6aSJordan Rife 
402*94682d6aSJordan Rife void test_sock_post_bind(void)
403*94682d6aSJordan Rife {
404*94682d6aSJordan Rife 	struct netns_obj *ns;
405*94682d6aSJordan Rife 	int cgroup_fd;
406*94682d6aSJordan Rife 	int i;
407*94682d6aSJordan Rife 
408*94682d6aSJordan Rife 	cgroup_fd = test__join_cgroup("/post_bind");
409*94682d6aSJordan Rife 	if (!ASSERT_OK_FD(cgroup_fd, "join_cgroup"))
410*94682d6aSJordan Rife 		return;
411*94682d6aSJordan Rife 
412*94682d6aSJordan Rife 	ns = netns_new(TEST_NS, true);
413*94682d6aSJordan Rife 	if (!ASSERT_OK_PTR(ns, "netns_new"))
414*94682d6aSJordan Rife 		goto cleanup;
415*94682d6aSJordan Rife 
416*94682d6aSJordan Rife 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
417*94682d6aSJordan Rife 		if (!test__start_subtest(tests[i].descr))
418*94682d6aSJordan Rife 			continue;
419*94682d6aSJordan Rife 
420*94682d6aSJordan Rife 		ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr);
421*94682d6aSJordan Rife 	}
422*94682d6aSJordan Rife 
423*94682d6aSJordan Rife cleanup:
424*94682d6aSJordan Rife 	netns_free(ns);
425*94682d6aSJordan Rife 	close(cgroup_fd);
426*94682d6aSJordan Rife }
427