xref: /linux/tools/testing/selftests/bpf/progs/sockopt_multi.c (revision 8e1bb4a41aa78d6105e59186af3dcd545fc66e70)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <netinet/in.h>
3 #include <linux/bpf.h>
4 #include <bpf/bpf_helpers.h>
5 
6 char _license[] SEC("license") = "GPL";
7 
8 __s32 page_size = 0;
9 
10 SEC("cgroup/getsockopt")
11 int _getsockopt_child(struct bpf_sockopt *ctx)
12 {
13 	__u8 *optval_end = ctx->optval_end;
14 	__u8 *optval = ctx->optval;
15 
16 	if (ctx->level != SOL_IP || ctx->optname != IP_TOS)
17 		goto out;
18 
19 	if (optval + 1 > optval_end)
20 		return 0; /* EPERM, bounds check */
21 
22 	if (optval[0] != 0x80)
23 		return 0; /* EPERM, unexpected optval from the kernel */
24 
25 	ctx->retval = 0; /* Reset system call return value to zero */
26 
27 	optval[0] = 0x90;
28 	ctx->optlen = 1;
29 
30 	return 1;
31 
32 out:
33 	/* optval larger than PAGE_SIZE use kernel's buffer. */
34 	if (ctx->optlen > page_size)
35 		ctx->optlen = 0;
36 	return 1;
37 }
38 
39 SEC("cgroup/getsockopt")
40 int _getsockopt_parent(struct bpf_sockopt *ctx)
41 {
42 	__u8 *optval_end = ctx->optval_end;
43 	__u8 *optval = ctx->optval;
44 
45 	if (ctx->level != SOL_IP || ctx->optname != IP_TOS)
46 		goto out;
47 
48 	if (optval + 1 > optval_end)
49 		return 0; /* EPERM, bounds check */
50 
51 	if (optval[0] != 0x90)
52 		return 0; /* EPERM, unexpected optval from the kernel */
53 
54 	ctx->retval = 0; /* Reset system call return value to zero */
55 
56 	optval[0] = 0xA0;
57 	ctx->optlen = 1;
58 
59 	return 1;
60 
61 out:
62 	/* optval larger than PAGE_SIZE use kernel's buffer. */
63 	if (ctx->optlen > page_size)
64 		ctx->optlen = 0;
65 	return 1;
66 }
67 
68 SEC("cgroup/setsockopt")
69 int _setsockopt(struct bpf_sockopt *ctx)
70 {
71 	__u8 *optval_end = ctx->optval_end;
72 	__u8 *optval = ctx->optval;
73 
74 	if (ctx->level != SOL_IP || ctx->optname != IP_TOS)
75 		goto out;
76 
77 	if (optval + 1 > optval_end)
78 		return 0; /* EPERM, bounds check */
79 
80 	optval[0] += 0x10;
81 	ctx->optlen = 1;
82 
83 	return 1;
84 
85 out:
86 	/* optval larger than PAGE_SIZE use kernel's buffer. */
87 	if (ctx->optlen > page_size)
88 		ctx->optlen = 0;
89 	return 1;
90 }
91