1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include "cgroup_helpers.h" 4 5 static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) 6 { 7 enum bpf_attach_type attach_type; 8 enum bpf_prog_type prog_type; 9 struct bpf_program *prog; 10 int err; 11 12 err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); 13 if (err) { 14 log_err("Failed to deduct types for %s BPF program", title); 15 return -1; 16 } 17 18 prog = bpf_object__find_program_by_title(obj, title); 19 if (!prog) { 20 log_err("Failed to find %s BPF program", title); 21 return -1; 22 } 23 24 err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, 25 attach_type, BPF_F_ALLOW_MULTI); 26 if (err) { 27 log_err("Failed to attach %s BPF program", title); 28 return -1; 29 } 30 31 return 0; 32 } 33 34 static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title) 35 { 36 enum bpf_attach_type attach_type; 37 enum bpf_prog_type prog_type; 38 struct bpf_program *prog; 39 int err; 40 41 err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); 42 if (err) 43 return -1; 44 45 prog = bpf_object__find_program_by_title(obj, title); 46 if (!prog) 47 return -1; 48 49 err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd, 50 attach_type); 51 if (err) 52 return -1; 53 54 return 0; 55 } 56 57 static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, 58 int cg_child, int sock_fd) 59 { 60 socklen_t optlen; 61 __u8 buf; 62 int err; 63 64 /* Set IP_TOS to the expected value (0x80). */ 65 66 buf = 0x80; 67 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 68 if (err < 0) { 69 log_err("Failed to call setsockopt(IP_TOS)"); 70 goto detach; 71 } 72 73 buf = 0x00; 74 optlen = 1; 75 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 76 if (err) { 77 log_err("Failed to call getsockopt(IP_TOS)"); 78 goto detach; 79 } 80 81 if (buf != 0x80) { 82 log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); 83 err = -1; 84 goto detach; 85 } 86 87 /* Attach child program and make sure it returns new value: 88 * - kernel: -> 0x80 89 * - child: 0x80 -> 0x90 90 */ 91 92 err = prog_attach(obj, cg_child, "cgroup/getsockopt/child"); 93 if (err) 94 goto detach; 95 96 buf = 0x00; 97 optlen = 1; 98 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 99 if (err) { 100 log_err("Failed to call getsockopt(IP_TOS)"); 101 goto detach; 102 } 103 104 if (buf != 0x90) { 105 log_err("Unexpected getsockopt 0x%x != 0x90", buf); 106 err = -1; 107 goto detach; 108 } 109 110 /* Attach parent program and make sure it returns new value: 111 * - kernel: -> 0x80 112 * - child: 0x80 -> 0x90 113 * - parent: 0x90 -> 0xA0 114 */ 115 116 err = prog_attach(obj, cg_parent, "cgroup/getsockopt/parent"); 117 if (err) 118 goto detach; 119 120 buf = 0x00; 121 optlen = 1; 122 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 123 if (err) { 124 log_err("Failed to call getsockopt(IP_TOS)"); 125 goto detach; 126 } 127 128 if (buf != 0xA0) { 129 log_err("Unexpected getsockopt 0x%x != 0xA0", buf); 130 err = -1; 131 goto detach; 132 } 133 134 /* Setting unexpected initial sockopt should return EPERM: 135 * - kernel: -> 0x40 136 * - child: unexpected 0x40, EPERM 137 * - parent: unexpected 0x40, EPERM 138 */ 139 140 buf = 0x40; 141 if (setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1) < 0) { 142 log_err("Failed to call setsockopt(IP_TOS)"); 143 goto detach; 144 } 145 146 buf = 0x00; 147 optlen = 1; 148 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 149 if (!err) { 150 log_err("Unexpected success from getsockopt(IP_TOS)"); 151 goto detach; 152 } 153 154 /* Detach child program and make sure we still get EPERM: 155 * - kernel: -> 0x40 156 * - parent: unexpected 0x40, EPERM 157 */ 158 159 err = prog_detach(obj, cg_child, "cgroup/getsockopt/child"); 160 if (err) { 161 log_err("Failed to detach child program"); 162 goto detach; 163 } 164 165 buf = 0x00; 166 optlen = 1; 167 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 168 if (!err) { 169 log_err("Unexpected success from getsockopt(IP_TOS)"); 170 goto detach; 171 } 172 173 /* Set initial value to the one the parent program expects: 174 * - kernel: -> 0x90 175 * - parent: 0x90 -> 0xA0 176 */ 177 178 buf = 0x90; 179 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 180 if (err < 0) { 181 log_err("Failed to call setsockopt(IP_TOS)"); 182 goto detach; 183 } 184 185 buf = 0x00; 186 optlen = 1; 187 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 188 if (err) { 189 log_err("Failed to call getsockopt(IP_TOS)"); 190 goto detach; 191 } 192 193 if (buf != 0xA0) { 194 log_err("Unexpected getsockopt 0x%x != 0xA0", buf); 195 err = -1; 196 goto detach; 197 } 198 199 detach: 200 prog_detach(obj, cg_child, "cgroup/getsockopt/child"); 201 prog_detach(obj, cg_parent, "cgroup/getsockopt/parent"); 202 203 return err; 204 } 205 206 static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, 207 int cg_child, int sock_fd) 208 { 209 socklen_t optlen; 210 __u8 buf; 211 int err; 212 213 /* Set IP_TOS to the expected value (0x80). */ 214 215 buf = 0x80; 216 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 217 if (err < 0) { 218 log_err("Failed to call setsockopt(IP_TOS)"); 219 goto detach; 220 } 221 222 buf = 0x00; 223 optlen = 1; 224 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 225 if (err) { 226 log_err("Failed to call getsockopt(IP_TOS)"); 227 goto detach; 228 } 229 230 if (buf != 0x80) { 231 log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); 232 err = -1; 233 goto detach; 234 } 235 236 /* Attach child program and make sure it adds 0x10. */ 237 238 err = prog_attach(obj, cg_child, "cgroup/setsockopt"); 239 if (err) 240 goto detach; 241 242 buf = 0x80; 243 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 244 if (err < 0) { 245 log_err("Failed to call setsockopt(IP_TOS)"); 246 goto detach; 247 } 248 249 buf = 0x00; 250 optlen = 1; 251 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 252 if (err) { 253 log_err("Failed to call getsockopt(IP_TOS)"); 254 goto detach; 255 } 256 257 if (buf != 0x80 + 0x10) { 258 log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf); 259 err = -1; 260 goto detach; 261 } 262 263 /* Attach parent program and make sure it adds another 0x10. */ 264 265 err = prog_attach(obj, cg_parent, "cgroup/setsockopt"); 266 if (err) 267 goto detach; 268 269 buf = 0x80; 270 err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 271 if (err < 0) { 272 log_err("Failed to call setsockopt(IP_TOS)"); 273 goto detach; 274 } 275 276 buf = 0x00; 277 optlen = 1; 278 err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 279 if (err) { 280 log_err("Failed to call getsockopt(IP_TOS)"); 281 goto detach; 282 } 283 284 if (buf != 0x80 + 2 * 0x10) { 285 log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf); 286 err = -1; 287 goto detach; 288 } 289 290 detach: 291 prog_detach(obj, cg_child, "cgroup/setsockopt"); 292 prog_detach(obj, cg_parent, "cgroup/setsockopt"); 293 294 return err; 295 } 296 297 void test_sockopt_multi(void) 298 { 299 struct bpf_prog_load_attr attr = { 300 .file = "./sockopt_multi.o", 301 }; 302 int cg_parent = -1, cg_child = -1; 303 struct bpf_object *obj = NULL; 304 int sock_fd = -1; 305 int err = -1; 306 int ignored; 307 308 cg_parent = test__join_cgroup("/parent"); 309 if (CHECK_FAIL(cg_parent < 0)) 310 goto out; 311 312 cg_child = test__join_cgroup("/parent/child"); 313 if (CHECK_FAIL(cg_child < 0)) 314 goto out; 315 316 err = bpf_prog_load_xattr(&attr, &obj, &ignored); 317 if (CHECK_FAIL(err)) 318 goto out; 319 320 sock_fd = socket(AF_INET, SOCK_STREAM, 0); 321 if (CHECK_FAIL(sock_fd < 0)) 322 goto out; 323 324 CHECK_FAIL(run_getsockopt_test(obj, cg_parent, cg_child, sock_fd)); 325 CHECK_FAIL(run_setsockopt_test(obj, cg_parent, cg_child, sock_fd)); 326 327 out: 328 close(sock_fd); 329 bpf_object__close(obj); 330 close(cg_child); 331 close(cg_parent); 332 } 333