1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include "cgroup_helpers.h" 4 5 #define SOL_CUSTOM 0xdeadbeef 6 7 static 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; 129 err: 130 close(fd); 131 return -1; 132 } 133 134 static 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 163 static 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 186 close_bpf_object: 187 bpf_object__close(obj); 188 } 189 190 void 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 } 201