1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <test_progs.h>
3*4882a593Smuzhiyun #include "cgroup_helpers.h"
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun static char bpf_log_buf[4096];
6*4882a593Smuzhiyun static bool verbose;
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun enum sockopt_test_error {
9*4882a593Smuzhiyun OK = 0,
10*4882a593Smuzhiyun DENY_LOAD,
11*4882a593Smuzhiyun DENY_ATTACH,
12*4882a593Smuzhiyun EPERM_GETSOCKOPT,
13*4882a593Smuzhiyun EFAULT_GETSOCKOPT,
14*4882a593Smuzhiyun EPERM_SETSOCKOPT,
15*4882a593Smuzhiyun EFAULT_SETSOCKOPT,
16*4882a593Smuzhiyun };
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun static struct sockopt_test {
19*4882a593Smuzhiyun const char *descr;
20*4882a593Smuzhiyun const struct bpf_insn insns[64];
21*4882a593Smuzhiyun enum bpf_attach_type attach_type;
22*4882a593Smuzhiyun enum bpf_attach_type expected_attach_type;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun int set_optname;
25*4882a593Smuzhiyun int set_level;
26*4882a593Smuzhiyun const char set_optval[64];
27*4882a593Smuzhiyun socklen_t set_optlen;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun int get_optname;
30*4882a593Smuzhiyun int get_level;
31*4882a593Smuzhiyun const char get_optval[64];
32*4882a593Smuzhiyun socklen_t get_optlen;
33*4882a593Smuzhiyun socklen_t get_optlen_ret;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun enum sockopt_test_error error;
36*4882a593Smuzhiyun } tests[] = {
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* ==================== getsockopt ==================== */
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun .descr = "getsockopt: no expected_attach_type",
42*4882a593Smuzhiyun .insns = {
43*4882a593Smuzhiyun /* return 1 */
44*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
45*4882a593Smuzhiyun BPF_EXIT_INSN(),
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun },
48*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
49*4882a593Smuzhiyun .expected_attach_type = 0,
50*4882a593Smuzhiyun .error = DENY_LOAD,
51*4882a593Smuzhiyun },
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun .descr = "getsockopt: wrong expected_attach_type",
54*4882a593Smuzhiyun .insns = {
55*4882a593Smuzhiyun /* return 1 */
56*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
57*4882a593Smuzhiyun BPF_EXIT_INSN(),
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun },
60*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
61*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
62*4882a593Smuzhiyun .error = DENY_ATTACH,
63*4882a593Smuzhiyun },
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun .descr = "getsockopt: bypass bpf hook",
66*4882a593Smuzhiyun .insns = {
67*4882a593Smuzhiyun /* return 1 */
68*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
69*4882a593Smuzhiyun BPF_EXIT_INSN(),
70*4882a593Smuzhiyun },
71*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
72*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun .get_level = SOL_IP,
75*4882a593Smuzhiyun .set_level = SOL_IP,
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun .get_optname = IP_TOS,
78*4882a593Smuzhiyun .set_optname = IP_TOS,
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun .set_optval = { 1 << 3 },
81*4882a593Smuzhiyun .set_optlen = 1,
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun .get_optval = { 1 << 3 },
84*4882a593Smuzhiyun .get_optlen = 1,
85*4882a593Smuzhiyun },
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun .descr = "getsockopt: return EPERM from bpf hook",
88*4882a593Smuzhiyun .insns = {
89*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
90*4882a593Smuzhiyun BPF_EXIT_INSN(),
91*4882a593Smuzhiyun },
92*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
93*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun .get_level = SOL_IP,
96*4882a593Smuzhiyun .get_optname = IP_TOS,
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun .get_optlen = 1,
99*4882a593Smuzhiyun .error = EPERM_GETSOCKOPT,
100*4882a593Smuzhiyun },
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun .descr = "getsockopt: no optval bounds check, deny loading",
103*4882a593Smuzhiyun .insns = {
104*4882a593Smuzhiyun /* r6 = ctx->optval */
105*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
106*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval)),
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* ctx->optval[0] = 0x80 */
109*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0x80),
110*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0),
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* return 1 */
113*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
114*4882a593Smuzhiyun BPF_EXIT_INSN(),
115*4882a593Smuzhiyun },
116*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
117*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
118*4882a593Smuzhiyun .error = DENY_LOAD,
119*4882a593Smuzhiyun },
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun .descr = "getsockopt: read ctx->level",
122*4882a593Smuzhiyun .insns = {
123*4882a593Smuzhiyun /* r6 = ctx->level */
124*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
125*4882a593Smuzhiyun offsetof(struct bpf_sockopt, level)),
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* if (ctx->level == 123) { */
128*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
129*4882a593Smuzhiyun /* ctx->retval = 0 */
130*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
131*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
132*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
133*4882a593Smuzhiyun /* return 1 */
134*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
135*4882a593Smuzhiyun BPF_JMP_A(1),
136*4882a593Smuzhiyun /* } else { */
137*4882a593Smuzhiyun /* return 0 */
138*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
139*4882a593Smuzhiyun /* } */
140*4882a593Smuzhiyun BPF_EXIT_INSN(),
141*4882a593Smuzhiyun },
142*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
143*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun .get_level = 123,
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun .get_optlen = 1,
148*4882a593Smuzhiyun },
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun .descr = "getsockopt: deny writing to ctx->level",
151*4882a593Smuzhiyun .insns = {
152*4882a593Smuzhiyun /* ctx->level = 1 */
153*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
154*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
155*4882a593Smuzhiyun offsetof(struct bpf_sockopt, level)),
156*4882a593Smuzhiyun BPF_EXIT_INSN(),
157*4882a593Smuzhiyun },
158*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
159*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun .error = DENY_LOAD,
162*4882a593Smuzhiyun },
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun .descr = "getsockopt: read ctx->optname",
165*4882a593Smuzhiyun .insns = {
166*4882a593Smuzhiyun /* r6 = ctx->optname */
167*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
168*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optname)),
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /* if (ctx->optname == 123) { */
171*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
172*4882a593Smuzhiyun /* ctx->retval = 0 */
173*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
174*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
175*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
176*4882a593Smuzhiyun /* return 1 */
177*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
178*4882a593Smuzhiyun BPF_JMP_A(1),
179*4882a593Smuzhiyun /* } else { */
180*4882a593Smuzhiyun /* return 0 */
181*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
182*4882a593Smuzhiyun /* } */
183*4882a593Smuzhiyun BPF_EXIT_INSN(),
184*4882a593Smuzhiyun },
185*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
186*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun .get_optname = 123,
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun .get_optlen = 1,
191*4882a593Smuzhiyun },
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun .descr = "getsockopt: read ctx->retval",
194*4882a593Smuzhiyun .insns = {
195*4882a593Smuzhiyun /* r6 = ctx->retval */
196*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
197*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* return 1 */
200*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
201*4882a593Smuzhiyun BPF_EXIT_INSN(),
202*4882a593Smuzhiyun },
203*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
204*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun .get_level = SOL_IP,
207*4882a593Smuzhiyun .get_optname = IP_TOS,
208*4882a593Smuzhiyun .get_optlen = 1,
209*4882a593Smuzhiyun },
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun .descr = "getsockopt: deny writing to ctx->optname",
212*4882a593Smuzhiyun .insns = {
213*4882a593Smuzhiyun /* ctx->optname = 1 */
214*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
215*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
216*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optname)),
217*4882a593Smuzhiyun BPF_EXIT_INSN(),
218*4882a593Smuzhiyun },
219*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
220*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun .error = DENY_LOAD,
223*4882a593Smuzhiyun },
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun .descr = "getsockopt: read ctx->optlen",
226*4882a593Smuzhiyun .insns = {
227*4882a593Smuzhiyun /* r6 = ctx->optlen */
228*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
229*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /* if (ctx->optlen == 64) { */
232*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
233*4882a593Smuzhiyun /* ctx->retval = 0 */
234*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
235*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
236*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
237*4882a593Smuzhiyun /* return 1 */
238*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
239*4882a593Smuzhiyun BPF_JMP_A(1),
240*4882a593Smuzhiyun /* } else { */
241*4882a593Smuzhiyun /* return 0 */
242*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
243*4882a593Smuzhiyun /* } */
244*4882a593Smuzhiyun BPF_EXIT_INSN(),
245*4882a593Smuzhiyun },
246*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
247*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun .get_optlen = 64,
250*4882a593Smuzhiyun },
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun .descr = "getsockopt: deny bigger ctx->optlen",
253*4882a593Smuzhiyun .insns = {
254*4882a593Smuzhiyun /* ctx->optlen = 65 */
255*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 65),
256*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
257*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun /* ctx->retval = 0 */
260*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
261*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
262*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /* return 1 */
265*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
266*4882a593Smuzhiyun BPF_EXIT_INSN(),
267*4882a593Smuzhiyun },
268*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
269*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun .get_optlen = 64,
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun .error = EFAULT_GETSOCKOPT,
274*4882a593Smuzhiyun },
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun .descr = "getsockopt: deny arbitrary ctx->retval",
277*4882a593Smuzhiyun .insns = {
278*4882a593Smuzhiyun /* ctx->retval = 123 */
279*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 123),
280*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
281*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun /* return 1 */
284*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
285*4882a593Smuzhiyun BPF_EXIT_INSN(),
286*4882a593Smuzhiyun },
287*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
288*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun .get_optlen = 64,
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun .error = EFAULT_GETSOCKOPT,
293*4882a593Smuzhiyun },
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun .descr = "getsockopt: support smaller ctx->optlen",
296*4882a593Smuzhiyun .insns = {
297*4882a593Smuzhiyun /* ctx->optlen = 32 */
298*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 32),
299*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
300*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
301*4882a593Smuzhiyun /* ctx->retval = 0 */
302*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
303*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
304*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
305*4882a593Smuzhiyun /* return 1 */
306*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
307*4882a593Smuzhiyun BPF_EXIT_INSN(),
308*4882a593Smuzhiyun },
309*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
310*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun .get_optlen = 64,
313*4882a593Smuzhiyun .get_optlen_ret = 32,
314*4882a593Smuzhiyun },
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun .descr = "getsockopt: deny writing to ctx->optval",
317*4882a593Smuzhiyun .insns = {
318*4882a593Smuzhiyun /* ctx->optval = 1 */
319*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
320*4882a593Smuzhiyun BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
321*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval)),
322*4882a593Smuzhiyun BPF_EXIT_INSN(),
323*4882a593Smuzhiyun },
324*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
325*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun .error = DENY_LOAD,
328*4882a593Smuzhiyun },
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun .descr = "getsockopt: deny writing to ctx->optval_end",
331*4882a593Smuzhiyun .insns = {
332*4882a593Smuzhiyun /* ctx->optval_end = 1 */
333*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
334*4882a593Smuzhiyun BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
335*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval_end)),
336*4882a593Smuzhiyun BPF_EXIT_INSN(),
337*4882a593Smuzhiyun },
338*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
339*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun .error = DENY_LOAD,
342*4882a593Smuzhiyun },
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun .descr = "getsockopt: rewrite value",
345*4882a593Smuzhiyun .insns = {
346*4882a593Smuzhiyun /* r6 = ctx->optval */
347*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
348*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval)),
349*4882a593Smuzhiyun /* r2 = ctx->optval */
350*4882a593Smuzhiyun BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
351*4882a593Smuzhiyun /* r6 = ctx->optval + 1 */
352*4882a593Smuzhiyun BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun /* r7 = ctx->optval_end */
355*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
356*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval_end)),
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun /* if (ctx->optval + 1 <= ctx->optval_end) { */
359*4882a593Smuzhiyun BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
360*4882a593Smuzhiyun /* ctx->optval[0] = 0xF0 */
361*4882a593Smuzhiyun BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0),
362*4882a593Smuzhiyun /* } */
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /* ctx->retval = 0 */
365*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
366*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
367*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun /* return 1*/
370*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
371*4882a593Smuzhiyun BPF_EXIT_INSN(),
372*4882a593Smuzhiyun },
373*4882a593Smuzhiyun .attach_type = BPF_CGROUP_GETSOCKOPT,
374*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun .get_level = SOL_IP,
377*4882a593Smuzhiyun .get_optname = IP_TOS,
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun .get_optval = { 0xF0 },
380*4882a593Smuzhiyun .get_optlen = 1,
381*4882a593Smuzhiyun },
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /* ==================== setsockopt ==================== */
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun .descr = "setsockopt: no expected_attach_type",
387*4882a593Smuzhiyun .insns = {
388*4882a593Smuzhiyun /* return 1 */
389*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
390*4882a593Smuzhiyun BPF_EXIT_INSN(),
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun },
393*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
394*4882a593Smuzhiyun .expected_attach_type = 0,
395*4882a593Smuzhiyun .error = DENY_LOAD,
396*4882a593Smuzhiyun },
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun .descr = "setsockopt: wrong expected_attach_type",
399*4882a593Smuzhiyun .insns = {
400*4882a593Smuzhiyun /* return 1 */
401*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
402*4882a593Smuzhiyun BPF_EXIT_INSN(),
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun },
405*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
406*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
407*4882a593Smuzhiyun .error = DENY_ATTACH,
408*4882a593Smuzhiyun },
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun .descr = "setsockopt: bypass bpf hook",
411*4882a593Smuzhiyun .insns = {
412*4882a593Smuzhiyun /* return 1 */
413*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
414*4882a593Smuzhiyun BPF_EXIT_INSN(),
415*4882a593Smuzhiyun },
416*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
417*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun .get_level = SOL_IP,
420*4882a593Smuzhiyun .set_level = SOL_IP,
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun .get_optname = IP_TOS,
423*4882a593Smuzhiyun .set_optname = IP_TOS,
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun .set_optval = { 1 << 3 },
426*4882a593Smuzhiyun .set_optlen = 1,
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun .get_optval = { 1 << 3 },
429*4882a593Smuzhiyun .get_optlen = 1,
430*4882a593Smuzhiyun },
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun .descr = "setsockopt: return EPERM from bpf hook",
433*4882a593Smuzhiyun .insns = {
434*4882a593Smuzhiyun /* return 0 */
435*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
436*4882a593Smuzhiyun BPF_EXIT_INSN(),
437*4882a593Smuzhiyun },
438*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
439*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun .set_level = SOL_IP,
442*4882a593Smuzhiyun .set_optname = IP_TOS,
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun .set_optlen = 1,
445*4882a593Smuzhiyun .error = EPERM_SETSOCKOPT,
446*4882a593Smuzhiyun },
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun .descr = "setsockopt: no optval bounds check, deny loading",
449*4882a593Smuzhiyun .insns = {
450*4882a593Smuzhiyun /* r6 = ctx->optval */
451*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
452*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval)),
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /* r0 = ctx->optval[0] */
455*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0),
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun /* return 1 */
458*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
459*4882a593Smuzhiyun BPF_EXIT_INSN(),
460*4882a593Smuzhiyun },
461*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
462*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
463*4882a593Smuzhiyun .error = DENY_LOAD,
464*4882a593Smuzhiyun },
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun .descr = "setsockopt: read ctx->level",
467*4882a593Smuzhiyun .insns = {
468*4882a593Smuzhiyun /* r6 = ctx->level */
469*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
470*4882a593Smuzhiyun offsetof(struct bpf_sockopt, level)),
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun /* if (ctx->level == 123) { */
473*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
474*4882a593Smuzhiyun /* ctx->optlen = -1 */
475*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, -1),
476*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
477*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
478*4882a593Smuzhiyun /* return 1 */
479*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
480*4882a593Smuzhiyun BPF_JMP_A(1),
481*4882a593Smuzhiyun /* } else { */
482*4882a593Smuzhiyun /* return 0 */
483*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
484*4882a593Smuzhiyun /* } */
485*4882a593Smuzhiyun BPF_EXIT_INSN(),
486*4882a593Smuzhiyun },
487*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
488*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun .set_level = 123,
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun .set_optlen = 1,
493*4882a593Smuzhiyun },
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun .descr = "setsockopt: allow changing ctx->level",
496*4882a593Smuzhiyun .insns = {
497*4882a593Smuzhiyun /* ctx->level = SOL_IP */
498*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, SOL_IP),
499*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
500*4882a593Smuzhiyun offsetof(struct bpf_sockopt, level)),
501*4882a593Smuzhiyun /* return 1 */
502*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
503*4882a593Smuzhiyun BPF_EXIT_INSN(),
504*4882a593Smuzhiyun },
505*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
506*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun .get_level = SOL_IP,
509*4882a593Smuzhiyun .set_level = 234, /* should be rewritten to SOL_IP */
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun .get_optname = IP_TOS,
512*4882a593Smuzhiyun .set_optname = IP_TOS,
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun .set_optval = { 1 << 3 },
515*4882a593Smuzhiyun .set_optlen = 1,
516*4882a593Smuzhiyun .get_optval = { 1 << 3 },
517*4882a593Smuzhiyun .get_optlen = 1,
518*4882a593Smuzhiyun },
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun .descr = "setsockopt: read ctx->optname",
521*4882a593Smuzhiyun .insns = {
522*4882a593Smuzhiyun /* r6 = ctx->optname */
523*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
524*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optname)),
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /* if (ctx->optname == 123) { */
527*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
528*4882a593Smuzhiyun /* ctx->optlen = -1 */
529*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, -1),
530*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
531*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
532*4882a593Smuzhiyun /* return 1 */
533*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
534*4882a593Smuzhiyun BPF_JMP_A(1),
535*4882a593Smuzhiyun /* } else { */
536*4882a593Smuzhiyun /* return 0 */
537*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
538*4882a593Smuzhiyun /* } */
539*4882a593Smuzhiyun BPF_EXIT_INSN(),
540*4882a593Smuzhiyun },
541*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
542*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun .set_optname = 123,
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun .set_optlen = 1,
547*4882a593Smuzhiyun },
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun .descr = "setsockopt: allow changing ctx->optname",
550*4882a593Smuzhiyun .insns = {
551*4882a593Smuzhiyun /* ctx->optname = IP_TOS */
552*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, IP_TOS),
553*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
554*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optname)),
555*4882a593Smuzhiyun /* return 1 */
556*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
557*4882a593Smuzhiyun BPF_EXIT_INSN(),
558*4882a593Smuzhiyun },
559*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
560*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun .get_level = SOL_IP,
563*4882a593Smuzhiyun .set_level = SOL_IP,
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun .get_optname = IP_TOS,
566*4882a593Smuzhiyun .set_optname = 456, /* should be rewritten to IP_TOS */
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun .set_optval = { 1 << 3 },
569*4882a593Smuzhiyun .set_optlen = 1,
570*4882a593Smuzhiyun .get_optval = { 1 << 3 },
571*4882a593Smuzhiyun .get_optlen = 1,
572*4882a593Smuzhiyun },
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun .descr = "setsockopt: read ctx->optlen",
575*4882a593Smuzhiyun .insns = {
576*4882a593Smuzhiyun /* r6 = ctx->optlen */
577*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
578*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun /* if (ctx->optlen == 64) { */
581*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
582*4882a593Smuzhiyun /* ctx->optlen = -1 */
583*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, -1),
584*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
585*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
586*4882a593Smuzhiyun /* return 1 */
587*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
588*4882a593Smuzhiyun BPF_JMP_A(1),
589*4882a593Smuzhiyun /* } else { */
590*4882a593Smuzhiyun /* return 0 */
591*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
592*4882a593Smuzhiyun /* } */
593*4882a593Smuzhiyun BPF_EXIT_INSN(),
594*4882a593Smuzhiyun },
595*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
596*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun .set_optlen = 64,
599*4882a593Smuzhiyun },
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun .descr = "setsockopt: ctx->optlen == -1 is ok",
602*4882a593Smuzhiyun .insns = {
603*4882a593Smuzhiyun /* ctx->optlen = -1 */
604*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, -1),
605*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
606*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
607*4882a593Smuzhiyun /* return 1 */
608*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
609*4882a593Smuzhiyun BPF_EXIT_INSN(),
610*4882a593Smuzhiyun },
611*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
612*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun .set_optlen = 64,
615*4882a593Smuzhiyun },
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun .descr = "setsockopt: deny ctx->optlen < 0 (except -1)",
618*4882a593Smuzhiyun .insns = {
619*4882a593Smuzhiyun /* ctx->optlen = -2 */
620*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, -2),
621*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
622*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
623*4882a593Smuzhiyun /* return 1 */
624*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
625*4882a593Smuzhiyun BPF_EXIT_INSN(),
626*4882a593Smuzhiyun },
627*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
628*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun .set_optlen = 4,
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun .error = EFAULT_SETSOCKOPT,
633*4882a593Smuzhiyun },
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun .descr = "setsockopt: deny ctx->optlen > input optlen",
636*4882a593Smuzhiyun .insns = {
637*4882a593Smuzhiyun /* ctx->optlen = 65 */
638*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 65),
639*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
640*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
641*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
642*4882a593Smuzhiyun BPF_EXIT_INSN(),
643*4882a593Smuzhiyun },
644*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
645*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun .set_optlen = 64,
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun .error = EFAULT_SETSOCKOPT,
650*4882a593Smuzhiyun },
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun .descr = "setsockopt: allow changing ctx->optlen within bounds",
653*4882a593Smuzhiyun .insns = {
654*4882a593Smuzhiyun /* r6 = ctx->optval */
655*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
656*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval)),
657*4882a593Smuzhiyun /* r2 = ctx->optval */
658*4882a593Smuzhiyun BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
659*4882a593Smuzhiyun /* r6 = ctx->optval + 1 */
660*4882a593Smuzhiyun BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun /* r7 = ctx->optval_end */
663*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
664*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval_end)),
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun /* if (ctx->optval + 1 <= ctx->optval_end) { */
667*4882a593Smuzhiyun BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
668*4882a593Smuzhiyun /* ctx->optval[0] = 1 << 3 */
669*4882a593Smuzhiyun BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 1 << 3),
670*4882a593Smuzhiyun /* } */
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun /* ctx->optlen = 1 */
673*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
674*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
675*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optlen)),
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /* return 1*/
678*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
679*4882a593Smuzhiyun BPF_EXIT_INSN(),
680*4882a593Smuzhiyun },
681*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
682*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun .get_level = SOL_IP,
685*4882a593Smuzhiyun .set_level = SOL_IP,
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun .get_optname = IP_TOS,
688*4882a593Smuzhiyun .set_optname = IP_TOS,
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun .set_optval = { 1, 1, 1, 1 },
691*4882a593Smuzhiyun .set_optlen = 4,
692*4882a593Smuzhiyun .get_optval = { 1 << 3 },
693*4882a593Smuzhiyun .get_optlen = 1,
694*4882a593Smuzhiyun },
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun .descr = "setsockopt: deny write ctx->retval",
697*4882a593Smuzhiyun .insns = {
698*4882a593Smuzhiyun /* ctx->retval = 0 */
699*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
700*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
701*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun /* return 1 */
704*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
705*4882a593Smuzhiyun BPF_EXIT_INSN(),
706*4882a593Smuzhiyun },
707*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
708*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun .error = DENY_LOAD,
711*4882a593Smuzhiyun },
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun .descr = "setsockopt: deny read ctx->retval",
714*4882a593Smuzhiyun .insns = {
715*4882a593Smuzhiyun /* r6 = ctx->retval */
716*4882a593Smuzhiyun BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
717*4882a593Smuzhiyun offsetof(struct bpf_sockopt, retval)),
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun /* return 1 */
720*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
721*4882a593Smuzhiyun BPF_EXIT_INSN(),
722*4882a593Smuzhiyun },
723*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
724*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun .error = DENY_LOAD,
727*4882a593Smuzhiyun },
728*4882a593Smuzhiyun {
729*4882a593Smuzhiyun .descr = "setsockopt: deny writing to ctx->optval",
730*4882a593Smuzhiyun .insns = {
731*4882a593Smuzhiyun /* ctx->optval = 1 */
732*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
733*4882a593Smuzhiyun BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
734*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval)),
735*4882a593Smuzhiyun BPF_EXIT_INSN(),
736*4882a593Smuzhiyun },
737*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
738*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun .error = DENY_LOAD,
741*4882a593Smuzhiyun },
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun .descr = "setsockopt: deny writing to ctx->optval_end",
744*4882a593Smuzhiyun .insns = {
745*4882a593Smuzhiyun /* ctx->optval_end = 1 */
746*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
747*4882a593Smuzhiyun BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
748*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval_end)),
749*4882a593Smuzhiyun BPF_EXIT_INSN(),
750*4882a593Smuzhiyun },
751*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
752*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun .error = DENY_LOAD,
755*4882a593Smuzhiyun },
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun .descr = "setsockopt: allow IP_TOS <= 128",
758*4882a593Smuzhiyun .insns = {
759*4882a593Smuzhiyun /* r6 = ctx->optval */
760*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
761*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval)),
762*4882a593Smuzhiyun /* r7 = ctx->optval + 1 */
763*4882a593Smuzhiyun BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
764*4882a593Smuzhiyun BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun /* r8 = ctx->optval_end */
767*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
768*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval_end)),
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun /* if (ctx->optval + 1 <= ctx->optval_end) { */
771*4882a593Smuzhiyun BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun /* r9 = ctx->optval[0] */
774*4882a593Smuzhiyun BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun /* if (ctx->optval[0] < 128) */
777*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
778*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
779*4882a593Smuzhiyun BPF_JMP_A(1),
780*4882a593Smuzhiyun /* } */
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun /* } else { */
783*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
784*4882a593Smuzhiyun /* } */
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun BPF_EXIT_INSN(),
787*4882a593Smuzhiyun },
788*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
789*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun .get_level = SOL_IP,
792*4882a593Smuzhiyun .set_level = SOL_IP,
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun .get_optname = IP_TOS,
795*4882a593Smuzhiyun .set_optname = IP_TOS,
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun .set_optval = { 0x80 },
798*4882a593Smuzhiyun .set_optlen = 1,
799*4882a593Smuzhiyun .get_optval = { 0x80 },
800*4882a593Smuzhiyun .get_optlen = 1,
801*4882a593Smuzhiyun },
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun .descr = "setsockopt: deny IP_TOS > 128",
804*4882a593Smuzhiyun .insns = {
805*4882a593Smuzhiyun /* r6 = ctx->optval */
806*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
807*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval)),
808*4882a593Smuzhiyun /* r7 = ctx->optval + 1 */
809*4882a593Smuzhiyun BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
810*4882a593Smuzhiyun BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun /* r8 = ctx->optval_end */
813*4882a593Smuzhiyun BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
814*4882a593Smuzhiyun offsetof(struct bpf_sockopt, optval_end)),
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun /* if (ctx->optval + 1 <= ctx->optval_end) { */
817*4882a593Smuzhiyun BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun /* r9 = ctx->optval[0] */
820*4882a593Smuzhiyun BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun /* if (ctx->optval[0] < 128) */
823*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
824*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 1),
825*4882a593Smuzhiyun BPF_JMP_A(1),
826*4882a593Smuzhiyun /* } */
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun /* } else { */
829*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0),
830*4882a593Smuzhiyun /* } */
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun BPF_EXIT_INSN(),
833*4882a593Smuzhiyun },
834*4882a593Smuzhiyun .attach_type = BPF_CGROUP_SETSOCKOPT,
835*4882a593Smuzhiyun .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun .get_level = SOL_IP,
838*4882a593Smuzhiyun .set_level = SOL_IP,
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun .get_optname = IP_TOS,
841*4882a593Smuzhiyun .set_optname = IP_TOS,
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun .set_optval = { 0x81 },
844*4882a593Smuzhiyun .set_optlen = 1,
845*4882a593Smuzhiyun .get_optval = { 0x00 },
846*4882a593Smuzhiyun .get_optlen = 1,
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun .error = EPERM_SETSOCKOPT,
849*4882a593Smuzhiyun },
850*4882a593Smuzhiyun };
851*4882a593Smuzhiyun
load_prog(const struct bpf_insn * insns,enum bpf_attach_type expected_attach_type)852*4882a593Smuzhiyun static int load_prog(const struct bpf_insn *insns,
853*4882a593Smuzhiyun enum bpf_attach_type expected_attach_type)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun struct bpf_load_program_attr attr = {
856*4882a593Smuzhiyun .prog_type = BPF_PROG_TYPE_CGROUP_SOCKOPT,
857*4882a593Smuzhiyun .expected_attach_type = expected_attach_type,
858*4882a593Smuzhiyun .insns = insns,
859*4882a593Smuzhiyun .license = "GPL",
860*4882a593Smuzhiyun .log_level = 2,
861*4882a593Smuzhiyun };
862*4882a593Smuzhiyun int fd;
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun for (;
865*4882a593Smuzhiyun insns[attr.insns_cnt].code != (BPF_JMP | BPF_EXIT);
866*4882a593Smuzhiyun attr.insns_cnt++) {
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun attr.insns_cnt++;
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun fd = bpf_load_program_xattr(&attr, bpf_log_buf, sizeof(bpf_log_buf));
871*4882a593Smuzhiyun if (verbose && fd < 0)
872*4882a593Smuzhiyun fprintf(stderr, "%s\n", bpf_log_buf);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun return fd;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
run_test(int cgroup_fd,struct sockopt_test * test)877*4882a593Smuzhiyun static int run_test(int cgroup_fd, struct sockopt_test *test)
878*4882a593Smuzhiyun {
879*4882a593Smuzhiyun int sock_fd, err, prog_fd;
880*4882a593Smuzhiyun void *optval = NULL;
881*4882a593Smuzhiyun int ret = 0;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun prog_fd = load_prog(test->insns, test->expected_attach_type);
884*4882a593Smuzhiyun if (prog_fd < 0) {
885*4882a593Smuzhiyun if (test->error == DENY_LOAD)
886*4882a593Smuzhiyun return 0;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun log_err("Failed to load BPF program");
889*4882a593Smuzhiyun return -1;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
893*4882a593Smuzhiyun if (err < 0) {
894*4882a593Smuzhiyun if (test->error == DENY_ATTACH)
895*4882a593Smuzhiyun goto close_prog_fd;
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun log_err("Failed to attach BPF program");
898*4882a593Smuzhiyun ret = -1;
899*4882a593Smuzhiyun goto close_prog_fd;
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun sock_fd = socket(AF_INET, SOCK_STREAM, 0);
903*4882a593Smuzhiyun if (sock_fd < 0) {
904*4882a593Smuzhiyun log_err("Failed to create AF_INET socket");
905*4882a593Smuzhiyun ret = -1;
906*4882a593Smuzhiyun goto detach_prog;
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun if (test->set_optlen) {
910*4882a593Smuzhiyun err = setsockopt(sock_fd, test->set_level, test->set_optname,
911*4882a593Smuzhiyun test->set_optval, test->set_optlen);
912*4882a593Smuzhiyun if (err) {
913*4882a593Smuzhiyun if (errno == EPERM && test->error == EPERM_SETSOCKOPT)
914*4882a593Smuzhiyun goto close_sock_fd;
915*4882a593Smuzhiyun if (errno == EFAULT && test->error == EFAULT_SETSOCKOPT)
916*4882a593Smuzhiyun goto free_optval;
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun log_err("Failed to call setsockopt");
919*4882a593Smuzhiyun ret = -1;
920*4882a593Smuzhiyun goto close_sock_fd;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun }
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun if (test->get_optlen) {
925*4882a593Smuzhiyun optval = malloc(test->get_optlen);
926*4882a593Smuzhiyun socklen_t optlen = test->get_optlen;
927*4882a593Smuzhiyun socklen_t expected_get_optlen = test->get_optlen_ret ?:
928*4882a593Smuzhiyun test->get_optlen;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun err = getsockopt(sock_fd, test->get_level, test->get_optname,
931*4882a593Smuzhiyun optval, &optlen);
932*4882a593Smuzhiyun if (err) {
933*4882a593Smuzhiyun if (errno == EPERM && test->error == EPERM_GETSOCKOPT)
934*4882a593Smuzhiyun goto free_optval;
935*4882a593Smuzhiyun if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT)
936*4882a593Smuzhiyun goto free_optval;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun log_err("Failed to call getsockopt");
939*4882a593Smuzhiyun ret = -1;
940*4882a593Smuzhiyun goto free_optval;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun if (optlen != expected_get_optlen) {
944*4882a593Smuzhiyun errno = 0;
945*4882a593Smuzhiyun log_err("getsockopt returned unexpected optlen");
946*4882a593Smuzhiyun ret = -1;
947*4882a593Smuzhiyun goto free_optval;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun if (memcmp(optval, test->get_optval, optlen) != 0) {
951*4882a593Smuzhiyun errno = 0;
952*4882a593Smuzhiyun log_err("getsockopt returned unexpected optval");
953*4882a593Smuzhiyun ret = -1;
954*4882a593Smuzhiyun goto free_optval;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun ret = test->error != OK;
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun free_optval:
961*4882a593Smuzhiyun free(optval);
962*4882a593Smuzhiyun close_sock_fd:
963*4882a593Smuzhiyun close(sock_fd);
964*4882a593Smuzhiyun detach_prog:
965*4882a593Smuzhiyun bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);
966*4882a593Smuzhiyun close_prog_fd:
967*4882a593Smuzhiyun close(prog_fd);
968*4882a593Smuzhiyun return ret;
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun
test_sockopt(void)971*4882a593Smuzhiyun void test_sockopt(void)
972*4882a593Smuzhiyun {
973*4882a593Smuzhiyun int cgroup_fd, i;
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun cgroup_fd = test__join_cgroup("/sockopt");
976*4882a593Smuzhiyun if (CHECK_FAIL(cgroup_fd < 0))
977*4882a593Smuzhiyun return;
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(tests); i++) {
980*4882a593Smuzhiyun test__start_subtest(tests[i].descr);
981*4882a593Smuzhiyun CHECK_FAIL(run_test(cgroup_fd, &tests[i]));
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun close(cgroup_fd);
985*4882a593Smuzhiyun }
986