1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include "cgroup_helpers.h" 4 5 #include "sockopt_multi.skel.h" 6 7 static int run_getsockopt_test(struct sockopt_multi *obj, int cg_parent, 8 int cg_child, int sock_fd) 9 { 10 struct bpf_link *link_parent = NULL; 11 struct bpf_link *link_child = NULL; 12 socklen_t optlen; 13 __u8 buf; 14 int err; 15 16 /* Set IP_TOS to the expected value (0x80). */ 17 18 buf = 0x80; 19 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 20 if (err < 0) { 21 log_err("Failed to call setsockopt(IP_TOS)"); 22 goto detach; 23 } 24 25 buf = 0x00; 26 optlen = 1; 27 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 28 if (err) { 29 log_err("Failed to call getsockopt(IP_TOS)"); 30 goto detach; 31 } 32 33 if (buf != 0x80) { 34 log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); 35 err = -1; 36 goto detach; 37 } 38 39 /* Attach child program and make sure it returns new value: 40 * - kernel: -> 0x80 41 * - child: 0x80 -> 0x90 42 */ 43 44 link_child = bpf_program__attach_cgroup(obj->progs._getsockopt_child, 45 cg_child); 46 if (!ASSERT_OK_PTR(link_child, "cg-attach-getsockopt_child")) 47 goto detach; 48 49 buf = 0x00; 50 optlen = 1; 51 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 52 if (err) { 53 log_err("Failed to call getsockopt(IP_TOS)"); 54 goto detach; 55 } 56 57 if (buf != 0x90) { 58 log_err("Unexpected getsockopt 0x%x != 0x90", buf); 59 err = -1; 60 goto detach; 61 } 62 63 /* Attach parent program and make sure it returns new value: 64 * - kernel: -> 0x80 65 * - child: 0x80 -> 0x90 66 * - parent: 0x90 -> 0xA0 67 */ 68 69 link_parent = bpf_program__attach_cgroup(obj->progs._getsockopt_parent, 70 cg_parent); 71 if (!ASSERT_OK_PTR(link_parent, "cg-attach-getsockopt_parent")) 72 goto detach; 73 74 buf = 0x00; 75 optlen = 1; 76 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 77 if (err) { 78 log_err("Failed to call getsockopt(IP_TOS)"); 79 goto detach; 80 } 81 82 if (buf != 0xA0) { 83 log_err("Unexpected getsockopt 0x%x != 0xA0", buf); 84 err = -1; 85 goto detach; 86 } 87 88 /* Setting unexpected initial sockopt should return EPERM: 89 * - kernel: -> 0x40 90 * - child: unexpected 0x40, EPERM 91 * - parent: unexpected 0x40, EPERM 92 */ 93 94 buf = 0x40; 95 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 96 if (err < 0) { 97 log_err("Failed to call setsockopt(IP_TOS)"); 98 goto detach; 99 } 100 101 buf = 0x00; 102 optlen = 1; 103 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 104 if (!err) { 105 log_err("Unexpected success from getsockopt(IP_TOS)"); 106 goto detach; 107 } 108 109 /* Detach child program and make sure we still get EPERM: 110 * - kernel: -> 0x40 111 * - parent: unexpected 0x40, EPERM 112 */ 113 114 bpf_link__destroy(link_child); 115 link_child = NULL; 116 117 buf = 0x00; 118 optlen = 1; 119 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 120 if (!err) { 121 log_err("Unexpected success from getsockopt(IP_TOS)"); 122 goto detach; 123 } 124 125 /* Set initial value to the one the parent program expects: 126 * - kernel: -> 0x90 127 * - parent: 0x90 -> 0xA0 128 */ 129 130 buf = 0x90; 131 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 132 if (err < 0) { 133 log_err("Failed to call setsockopt(IP_TOS)"); 134 goto detach; 135 } 136 137 buf = 0x00; 138 optlen = 1; 139 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 140 if (err) { 141 log_err("Failed to call getsockopt(IP_TOS)"); 142 goto detach; 143 } 144 145 if (buf != 0xA0) { 146 log_err("Unexpected getsockopt 0x%x != 0xA0", buf); 147 err = -1; 148 goto detach; 149 } 150 151 detach: 152 bpf_link__destroy(link_child); 153 bpf_link__destroy(link_parent); 154 155 return err; 156 } 157 158 static int run_setsockopt_test(struct sockopt_multi *obj, int cg_parent, 159 int cg_child, int sock_fd) 160 { 161 struct bpf_link *link_parent = NULL; 162 struct bpf_link *link_child = NULL; 163 socklen_t optlen; 164 __u8 buf; 165 int err; 166 167 /* Set IP_TOS to the expected value (0x80). */ 168 169 buf = 0x80; 170 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 171 if (err < 0) { 172 log_err("Failed to call setsockopt(IP_TOS)"); 173 goto detach; 174 } 175 176 buf = 0x00; 177 optlen = 1; 178 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 179 if (err) { 180 log_err("Failed to call getsockopt(IP_TOS)"); 181 goto detach; 182 } 183 184 if (buf != 0x80) { 185 log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); 186 err = -1; 187 goto detach; 188 } 189 190 /* Attach child program and make sure it adds 0x10. */ 191 192 link_child = bpf_program__attach_cgroup(obj->progs._setsockopt, 193 cg_child); 194 if (!ASSERT_OK_PTR(link_child, "cg-attach-setsockopt_child")) 195 goto detach; 196 197 buf = 0x80; 198 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 199 if (err < 0) { 200 log_err("Failed to call setsockopt(IP_TOS)"); 201 goto detach; 202 } 203 204 buf = 0x00; 205 optlen = 1; 206 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 207 if (err) { 208 log_err("Failed to call getsockopt(IP_TOS)"); 209 goto detach; 210 } 211 212 if (buf != 0x80 + 0x10) { 213 log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf); 214 err = -1; 215 goto detach; 216 } 217 218 /* Attach parent program and make sure it adds another 0x10. */ 219 220 link_parent = bpf_program__attach_cgroup(obj->progs._setsockopt, 221 cg_parent); 222 if (!ASSERT_OK_PTR(link_parent, "cg-attach-setsockopt_parent")) 223 goto detach; 224 225 buf = 0x80; 226 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 227 if (err < 0) { 228 log_err("Failed to call setsockopt(IP_TOS)"); 229 goto detach; 230 } 231 232 buf = 0x00; 233 optlen = 1; 234 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 235 if (err) { 236 log_err("Failed to call getsockopt(IP_TOS)"); 237 goto detach; 238 } 239 240 if (buf != 0x80 + 2 * 0x10) { 241 log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf); 242 err = -1; 243 goto detach; 244 } 245 246 detach: 247 bpf_link__destroy(link_child); 248 bpf_link__destroy(link_parent); 249 250 return err; 251 } 252 253 void test_sockopt_multi(void) 254 { 255 int cg_parent = -1, cg_child = -1; 256 struct sockopt_multi *obj = NULL; 257 int sock_fd = -1; 258 259 cg_parent = test__join_cgroup("/parent"); 260 if (!ASSERT_GE(cg_parent, 0, "join_cgroup /parent")) 261 goto out; 262 263 cg_child = test__join_cgroup("/parent/child"); 264 if (!ASSERT_GE(cg_child, 0, "join_cgroup /parent/child")) 265 goto out; 266 267 obj = sockopt_multi__open_and_load(); 268 if (!ASSERT_OK_PTR(obj, "skel-load")) 269 goto out; 270 271 obj->bss->page_size = sysconf(_SC_PAGESIZE); 272 273 sock_fd = socket(AF_INET, SOCK_STREAM, 0); 274 if (!ASSERT_GE(sock_fd, 0, "socket")) 275 goto out; 276 277 ASSERT_OK(run_getsockopt_test(obj, cg_parent, cg_child, sock_fd), "getsockopt_test"); 278 ASSERT_OK(run_setsockopt_test(obj, cg_parent, cg_child, sock_fd), "setsockopt_test"); 279 280 out: 281 close(sock_fd); 282 sockopt_multi__destroy(obj); 283 close(cg_child); 284 close(cg_parent); 285 } 286