Loading...
1// SPDX-License-Identifier: GPL-2.0
2#include <test_progs.h>
3#include "cgroup_helpers.h"
4
5#define SOL_CUSTOM 0xdeadbeef
6
7static int getsetsockopt(void)
8{
9 int fd, err;
10 union {
11 char u8[4];
12 __u32 u32;
13 char cc[16]; /* TCP_CA_NAME_MAX */
14 } buf = {};
15 socklen_t optlen;
16
17 fd = socket(AF_INET, SOCK_STREAM, 0);
18 if (fd < 0) {
19 log_err("Failed to create socket");
20 return -1;
21 }
22
23 /* IP_TOS - BPF bypass */
24
25 buf.u8[0] = 0x08;
26 err = setsockopt(fd, SOL_IP, IP_TOS, &buf, 1);
27 if (err) {
28 log_err("Failed to call setsockopt(IP_TOS)");
29 goto err;
30 }
31
32 buf.u8[0] = 0x00;
33 optlen = 1;
34 err = getsockopt(fd, SOL_IP, IP_TOS, &buf, &optlen);
35 if (err) {
36 log_err("Failed to call getsockopt(IP_TOS)");
37 goto err;
38 }
39
40 if (buf.u8[0] != 0x08) {
41 log_err("Unexpected getsockopt(IP_TOS) buf[0] 0x%02x != 0x08",
42 buf.u8[0]);
43 goto err;
44 }
45
46 /* IP_TTL - EPERM */
47
48 buf.u8[0] = 1;
49 err = setsockopt(fd, SOL_IP, IP_TTL, &buf, 1);
50 if (!err || errno != EPERM) {
51 log_err("Unexpected success from setsockopt(IP_TTL)");
52 goto err;
53 }
54
55 /* SOL_CUSTOM - handled by BPF */
56
57 buf.u8[0] = 0x01;
58 err = setsockopt(fd, SOL_CUSTOM, 0, &buf, 1);
59 if (err) {
60 log_err("Failed to call setsockopt");
61 goto err;
62 }
63
64 buf.u32 = 0x00;
65 optlen = 4;
66 err = getsockopt(fd, SOL_CUSTOM, 0, &buf, &optlen);
67 if (err) {
68 log_err("Failed to call getsockopt");
69 goto err;
70 }
71
72 if (optlen != 1) {
73 log_err("Unexpected optlen %d != 1", optlen);
74 goto err;
75 }
76 if (buf.u8[0] != 0x01) {
77 log_err("Unexpected buf[0] 0x%02x != 0x01", buf.u8[0]);
78 goto err;
79 }
80
81 /* SO_SNDBUF is overwritten */
82
83 buf.u32 = 0x01010101;
84 err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, 4);
85 if (err) {
86 log_err("Failed to call setsockopt(SO_SNDBUF)");
87 goto err;
88 }
89
90 buf.u32 = 0x00;
91 optlen = 4;
92 err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, &optlen);
93 if (err) {
94 log_err("Failed to call getsockopt(SO_SNDBUF)");
95 goto err;
96 }
97
98 if (buf.u32 != 0x55AA*2) {
99 log_err("Unexpected getsockopt(SO_SNDBUF) 0x%x != 0x55AA*2",
100 buf.u32);
101 goto err;
102 }
103
104 /* TCP_CONGESTION can extend the string */
105
106 strcpy(buf.cc, "nv");
107 err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv"));
108 if (err) {
109 log_err("Failed to call setsockopt(TCP_CONGESTION)");
110 goto err;
111 }
112
113
114 optlen = sizeof(buf.cc);
115 err = getsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, &optlen);
116 if (err) {
117 log_err("Failed to call getsockopt(TCP_CONGESTION)");
118 goto err;
119 }
120
121 if (strcmp(buf.cc, "cubic") != 0) {
122 log_err("Unexpected getsockopt(TCP_CONGESTION) %s != %s",
123 buf.cc, "cubic");
124 goto err;
125 }
126
127 close(fd);
128 return 0;
129err:
130 close(fd);
131 return -1;
132}
133
134static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
135{
136 enum bpf_attach_type attach_type;
137 enum bpf_prog_type prog_type;
138 struct bpf_program *prog;
139 int err;
140
141 err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
142 if (err) {
143 log_err("Failed to deduct types for %s BPF program", title);
144 return -1;
145 }
146
147 prog = bpf_object__find_program_by_title(obj, title);
148 if (!prog) {
149 log_err("Failed to find %s BPF program", title);
150 return -1;
151 }
152
153 err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd,
154 attach_type, 0);
155 if (err) {
156 log_err("Failed to attach %s BPF program", title);
157 return -1;
158 }
159
160 return 0;
161}
162
163static void run_test(int cgroup_fd)
164{
165 struct bpf_prog_load_attr attr = {
166 .file = "./sockopt_sk.o",
167 };
168 struct bpf_object *obj;
169 int ignored;
170 int err;
171
172 err = bpf_prog_load_xattr(&attr, &obj, &ignored);
173 if (CHECK_FAIL(err))
174 return;
175
176 err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt");
177 if (CHECK_FAIL(err))
178 goto close_bpf_object;
179
180 err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt");
181 if (CHECK_FAIL(err))
182 goto close_bpf_object;
183
184 CHECK_FAIL(getsetsockopt());
185
186close_bpf_object:
187 bpf_object__close(obj);
188}
189
190void test_sockopt_sk(void)
191{
192 int cgroup_fd;
193
194 cgroup_fd = test__join_cgroup("/sockopt_sk");
195 if (CHECK_FAIL(cgroup_fd < 0))
196 return;
197
198 run_test(cgroup_fd);
199 close(cgroup_fd);
200}
1// SPDX-License-Identifier: GPL-2.0
2#include <test_progs.h>
3#include "cgroup_helpers.h"
4
5#include <linux/tcp.h>
6#include "sockopt_sk.skel.h"
7
8#ifndef SOL_TCP
9#define SOL_TCP IPPROTO_TCP
10#endif
11
12#define SOL_CUSTOM 0xdeadbeef
13
14static int getsetsockopt(void)
15{
16 int fd, err;
17 union {
18 char u8[4];
19 __u32 u32;
20 char cc[16]; /* TCP_CA_NAME_MAX */
21 struct tcp_zerocopy_receive zc;
22 } buf = {};
23 socklen_t optlen;
24 char *big_buf = NULL;
25
26 fd = socket(AF_INET, SOCK_STREAM, 0);
27 if (fd < 0) {
28 log_err("Failed to create socket");
29 return -1;
30 }
31
32 /* IP_TOS - BPF bypass */
33
34 optlen = getpagesize() * 2;
35 big_buf = calloc(1, optlen);
36 if (!big_buf) {
37 log_err("Couldn't allocate two pages");
38 goto err;
39 }
40
41 *(int *)big_buf = 0x08;
42 err = setsockopt(fd, SOL_IP, IP_TOS, big_buf, optlen);
43 if (err) {
44 log_err("Failed to call setsockopt(IP_TOS)");
45 goto err;
46 }
47
48 memset(big_buf, 0, optlen);
49 optlen = 1;
50 err = getsockopt(fd, SOL_IP, IP_TOS, big_buf, &optlen);
51 if (err) {
52 log_err("Failed to call getsockopt(IP_TOS)");
53 goto err;
54 }
55
56 if (*big_buf != 0x08) {
57 log_err("Unexpected getsockopt(IP_TOS) optval 0x%x != 0x08",
58 (int)*big_buf);
59 goto err;
60 }
61
62 /* IP_TTL - EPERM */
63
64 buf.u8[0] = 1;
65 err = setsockopt(fd, SOL_IP, IP_TTL, &buf, 1);
66 if (!err || errno != EPERM) {
67 log_err("Unexpected success from setsockopt(IP_TTL)");
68 goto err;
69 }
70
71 /* SOL_CUSTOM - handled by BPF */
72
73 buf.u8[0] = 0x01;
74 err = setsockopt(fd, SOL_CUSTOM, 0, &buf, 1);
75 if (err) {
76 log_err("Failed to call setsockopt");
77 goto err;
78 }
79
80 buf.u32 = 0x00;
81 optlen = 4;
82 err = getsockopt(fd, SOL_CUSTOM, 0, &buf, &optlen);
83 if (err) {
84 log_err("Failed to call getsockopt");
85 goto err;
86 }
87
88 if (optlen != 1) {
89 log_err("Unexpected optlen %d != 1", optlen);
90 goto err;
91 }
92 if (buf.u8[0] != 0x01) {
93 log_err("Unexpected buf[0] 0x%02x != 0x01", buf.u8[0]);
94 goto err;
95 }
96
97 /* IP_FREEBIND - BPF can't access optval past PAGE_SIZE */
98
99 optlen = getpagesize() * 2;
100 memset(big_buf, 0, optlen);
101
102 err = setsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, optlen);
103 if (err != 0) {
104 log_err("Failed to call setsockopt, ret=%d", err);
105 goto err;
106 }
107
108 err = getsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, &optlen);
109 if (err != 0) {
110 log_err("Failed to call getsockopt, ret=%d", err);
111 goto err;
112 }
113
114 if (optlen != 1 || *(__u8 *)big_buf != 0x55) {
115 log_err("Unexpected IP_FREEBIND getsockopt, optlen=%d, optval=0x%x",
116 optlen, *(__u8 *)big_buf);
117 }
118
119 /* SO_SNDBUF is overwritten */
120
121 buf.u32 = 0x01010101;
122 err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, 4);
123 if (err) {
124 log_err("Failed to call setsockopt(SO_SNDBUF)");
125 goto err;
126 }
127
128 buf.u32 = 0x00;
129 optlen = 4;
130 err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, &optlen);
131 if (err) {
132 log_err("Failed to call getsockopt(SO_SNDBUF)");
133 goto err;
134 }
135
136 if (buf.u32 != 0x55AA*2) {
137 log_err("Unexpected getsockopt(SO_SNDBUF) 0x%x != 0x55AA*2",
138 buf.u32);
139 goto err;
140 }
141
142 /* TCP_CONGESTION can extend the string */
143
144 strcpy(buf.cc, "nv");
145 err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv"));
146 if (err) {
147 log_err("Failed to call setsockopt(TCP_CONGESTION)");
148 goto err;
149 }
150
151
152 optlen = sizeof(buf.cc);
153 err = getsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, &optlen);
154 if (err) {
155 log_err("Failed to call getsockopt(TCP_CONGESTION)");
156 goto err;
157 }
158
159 if (strcmp(buf.cc, "cubic") != 0) {
160 log_err("Unexpected getsockopt(TCP_CONGESTION) %s != %s",
161 buf.cc, "cubic");
162 goto err;
163 }
164
165 /* TCP_ZEROCOPY_RECEIVE triggers */
166 memset(&buf, 0, sizeof(buf));
167 optlen = sizeof(buf.zc);
168 err = getsockopt(fd, SOL_TCP, TCP_ZEROCOPY_RECEIVE, &buf, &optlen);
169 if (err) {
170 log_err("Unexpected getsockopt(TCP_ZEROCOPY_RECEIVE) err=%d errno=%d",
171 err, errno);
172 goto err;
173 }
174
175 memset(&buf, 0, sizeof(buf));
176 buf.zc.address = 12345; /* rejected by BPF */
177 optlen = sizeof(buf.zc);
178 errno = 0;
179 err = getsockopt(fd, SOL_TCP, TCP_ZEROCOPY_RECEIVE, &buf, &optlen);
180 if (errno != EPERM) {
181 log_err("Unexpected getsockopt(TCP_ZEROCOPY_RECEIVE) err=%d errno=%d",
182 err, errno);
183 goto err;
184 }
185
186 free(big_buf);
187 close(fd);
188 return 0;
189err:
190 free(big_buf);
191 close(fd);
192 return -1;
193}
194
195static void run_test(int cgroup_fd)
196{
197 struct sockopt_sk *skel;
198
199 skel = sockopt_sk__open_and_load();
200 if (!ASSERT_OK_PTR(skel, "skel_load"))
201 goto cleanup;
202
203 skel->bss->page_size = getpagesize();
204
205 skel->links._setsockopt =
206 bpf_program__attach_cgroup(skel->progs._setsockopt, cgroup_fd);
207 if (!ASSERT_OK_PTR(skel->links._setsockopt, "setsockopt_link"))
208 goto cleanup;
209
210 skel->links._getsockopt =
211 bpf_program__attach_cgroup(skel->progs._getsockopt, cgroup_fd);
212 if (!ASSERT_OK_PTR(skel->links._getsockopt, "getsockopt_link"))
213 goto cleanup;
214
215 ASSERT_OK(getsetsockopt(), "getsetsockopt");
216
217cleanup:
218 sockopt_sk__destroy(skel);
219}
220
221void test_sockopt_sk(void)
222{
223 int cgroup_fd;
224
225 cgroup_fd = test__join_cgroup("/sockopt_sk");
226 if (CHECK_FAIL(cgroup_fd < 0))
227 return;
228
229 run_test(cgroup_fd);
230 close(cgroup_fd);
231}